Могу ли я использовать методы расширения и LINQ в .NET 2.0 или 3.0?

Когда я пытаюсь добавить метод расширения с использованием среды выполнения .NET 2.0 или 3.0, я получаю сообщение об ошибке:

Невозможно определить новый метод расширения, потому что требуется компилятор type 'System.Runtime.CompilerServices.ExtensionAttribute' не может быть найденный. Вам не хватает ссылки на System.Core.dll?

Но я не могу найти System.Core в списке доступных ссылок, когда я пытаюсь добавить его в проект. Что мне нужно сделать, чтобы использовать методы расширения и, в свою очередь, LINQ в моих проектах?

Ответ 1

Методы расширения не были добавлены в .NET до 3.5. Однако это не было изменением для 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   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;
    }
}

Библиотека с полной повторной реализацией LINQ к объектам с уже добавленным ExtensionAttribute может быть найдена в LinqBridge project (Спасибо Аллон Гуральек).