ฉันสามารถใช้วิธีการขยายและ LINQ ใน .NET 2.0 หรือ 3.0 ได้หรือไม่

เมื่อฉันพยายามเพิ่มวิธีการขยายโดยใช้รันไทม์ .NET 2.0 หรือ 3.0 ฉันได้รับข้อผิดพลาด:

ไม่สามารถกำหนดวิธีการขยายใหม่ได้เนื่องจากไม่พบประเภท 'System.Runtime.CompilerServices.ExtensionAttribute' ของคอมไพเลอร์ คุณขาดการอ้างอิงถึง System.Core.dll หรือไม่?

แต่ฉันไม่พบ System.Core ในรายการข้อมูลอ้างอิงที่มีอยู่เมื่อฉันพยายามเพิ่มลงในโปรเจ็กต์ ฉันต้องทำอะไรบ้างเพื่อให้สามารถใช้วิธีการขยายได้ และในทางกลับกัน LINQ ในโครงการของฉัน ?


person Scott Chamberlain    schedule 05.07.2012    source แหล่งที่มา


คำตอบ (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 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;
    }
}

ไลบรารีที่มีการปรับใช้ LINQ ให้กับออบเจ็กต์ใหม่ทั้งหมดโดยเพิ่ม ExtensionAttribute เข้าไปแล้วสามารถพบได้ใน โครงการ LinqBridge (ขอขอบคุณ Allon Guralnek)

person Scott Chamberlain    schedule 05.07.2012
comment
สิ่งสำคัญคือต้องชี้ให้เห็นว่าวิธี LinqReplacement ของคุณจะใช้ได้กับ Linq to Objects เท่านั้น มันจะไม่ทำงานสำหรับ Linq ถึง Sql ดูเหมือนว่าผู้คนจำนวนมากไม่ทราบว่ามีความแตกต่าง แต่ก็ยัง +1 - person cadrell0; 05.07.2012
comment
คุณไม่จำเป็นต้องใช้วิธีการขยายซ้ำด้วยตนเอง ผู้ให้บริการ LINQ-to-Objects ที่สมบูรณ์ได้ถูกนำไปใช้ใหม่สำหรับ .NET 2.0 เมื่อนานมาแล้วในชื่อ LinqBridge และได้รวม ExtensionAttribute ไว้แล้ว ซึ่งช่วยให้คุณสร้างวิธีการขยายใน .NET 2.0 ด้วย VS 2008 ขึ้นไปได้ - person Allon Guralnek; 05.07.2012
comment
@AllonGuralnek ขอบคุณสำหรับลิงก์อัปเดตคำตอบและให้เครดิตคุณ - person Scott Chamberlain; 05.07.2012
comment
@ cadrell0 นั่นเป็นเรื่องจริงบางส่วน คุณยังคงสามารถใช้งานได้กับการเรียกไปยัง ADO.NET ที่ทำ while(reader.Read()) yield BuildObject(reader) แน่นอนว่ามันจะทำทุกอย่างในหน่วยความจำราวกับว่าคุณจุด .AsEnumerable() ทั่วทุกที่ และมันจะอ่านคอลัมน์ที่ไม่สนใจ แต่วิธีการดังกล่าวยังคงมีประโยชน์ในวันก่อน Linq - person Jon Hanna; 04.06.2014