拡張メソッドは、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に感謝します)。