13

.NET 2.0 または 3.0 ランタイムを使用して拡張メソッドを追加しようとすると、次のエラーが発生します。

コンパイラに必要な型 'System.Runtime.CompilerServices.ExtensionAttribute' が見つからないため、新しい拡張メソッドを定義できません。System.Core.dll への参照がありませんか?

しかし、System.Core をプロジェクトに追加しようとすると、使用可能な参照のリストに System.Core が見つかりません。プロジェクトで拡張メソッドを使用してLINQをオンにするには、どうすればよいですか?

4

1 に答える 1

28

拡張メソッドは、3.5 まで .NET に追加されませんでした。ただし、これは CLR の変更ではなく、それらを追加したコンパイラの変更であるため、2.0 および 3.0 プロジェクトで引き続き使用できます。この回避策を実行するには、3.5 プロジェクトを作成できるコンパイラが必要です (Visual Studio 2008 以降)。

拡張メソッドを実際に使用する必要がないため、拡張メソッドを使用しようとしたときに発生するエラーは誤解を招くものですSystem.Core.dll。拡張メソッドを使用すると、舞台裏でコンパイラが[Extension]属性を関数に追加します。属性の処理方法を理解するコンパイラが[Extension]あれば、自分で属性を作成すれば、2.0 および 3.0 プロジェクトでそれを使用できます。

次のクラスをプロジェクトに追加するだけで、拡張メソッドの使用を開始できます。

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
    public class ExtensionAttribute : Attribute
    {
    }
}

上記のコード ブロックはSystem.Core.Dll内にあるため、それらを使用するには DLL ファイルを含める必要があるというエラーが表示されます。


少し余分な作業が必要な LINQ 機能が必要な場合。拡張メソッドを自分で再実装する必要があります。LINQ to SQLの完全な機能を模倣するには、コードが非常に複雑になる可能性があります。ただし、 LINQ to Objectsを使用しているだけであれば、ほとんどの LINQ メソッドの実装は複雑ではありません。ここでは、作業を開始するために作成したプロジェクトの LINQ to Objects 置換関数をいくつか示します。

public static class LinqReplacement
{
    public delegate TResult Func<T, TResult>(T arg);
    public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);

    public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (predicate == null)
            throw new ArgumentNullException("predicate");

        foreach (TSource item in source)
        {
            if (predicate(item) == true)
                return item;
        }

        throw new InvalidOperationException("No item satisfied the predicate or the source collection was empty.");
    }

    public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
    {
        if (source == null)
            throw new ArgumentNullException("source");

        foreach (TSource item in source)
        {
            return item;
        }

        return default(TSource);
    }

    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
    {
        foreach (object item in source)
        {
            yield return (TResult)item;
        }
    }

    public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (selector == null)
            throw new ArgumentNullException("selector");

        foreach (TSource item in source)
        {
            foreach (TResult subItem in selector(item))
            {
                yield return subItem;
            }
        }
    }

    public static int Count<TSource>(this IEnumerable<TSource> source)
    {
        var asCollection = source as ICollection;
        if(asCollection != null)
        {
            return asCollection.Count;
        }

        int count = 0;
        foreach (TSource item in source)
        {
            checked //If we are counting a larger than int.MaxValue enumerable this will cause a OverflowException to happen when the counter wraps around.
            {
                count++;
            }
        }
        return count;
    }
}

ExtensionAttributeすでに追加されている LINQ to Objects を完全に再実装したライブラリは、 LinqBridgeプロジェクトにあります ( Allon Guralnekに感謝します)。

于 2012-07-05T14:34:58.330 に答える