【问题标题】:Can I use extension methods and LINQ in .NET 2.0 or 3.0?我可以在 .NET 2.0 或 3.0 中使用扩展方法和 LINQ 吗?
【发布时间】:2012-07-05 23:43:53
【问题描述】:

当我尝试使用 .NET 2.0 或 3.0 运行时添加扩展方法时,我收到错误:

无法定义新的扩展方法,因为编译器需要 类型“System.Runtime.CompilerServices.ExtensionAttribute”不能 成立。您是否缺少对 System.Core.dll 的引用?

但是当我尝试将 System.Core 添加到项目时,我无法在可用参考列表中找到它。我需要做什么才能在我的项目中使用扩展方法和LINQ

【问题讨论】:

    标签: c# .net .net-2.0 extension-methods .net-3.0


    【解决方案1】:

    扩展方法直到 3.5 才添加到 .NET。但是,不是对 CLR 的更改,而是 a change to the compiler 添加了它们,因此您仍然可以在 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;
        }
    }
    

    可以在LinqBridge 项目中找到一个完全重新实现 LINQ to Objects 并添加了ExtensionAttribute 的库(感谢Allon Guralnek)。

    【讨论】:

    • 重要的是要指出您的 LinqReplacement 方法仅适用于 Linq to Objects。它不适用于 Linq to Sql。似乎很多人没有意识到有区别。但仍然 +1
    • 您不必自己重新实现扩展方法。完整的 LINQ-to-Objects 提供程序早已在 .NET 2.0 中重新实现为 LinqBridge。它已经包含ExtensionAttribute,它允许您在 .NET 2.0 中使用 VS 2008 及更高版本创建扩展方法。
    • @AllonGuralnek 感谢您的链接,更新了答案并给了您信用。
    • @cadrell0 部分正确,您仍然可以将它与执行 while(reader.Read()) yield BuildObject(reader) 的 ADO.NET 调用一起使用。当然,它会在内存中做所有事情,就好像你在所有地方都点缀了.AsEnumerable(),它会读取它不关心的列,但是这种方法在 Linq 之前的日子里仍然有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-21
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多