Bisakah saya menggunakan metode ekstensi dan LINQ di .NET 2.0 atau 3.0?

Ketika saya mencoba menambahkan metode ekstensi menggunakan runtime .NET 2.0 atau 3.0, saya mendapatkan kesalahan:

Tidak dapat menentukan metode ekstensi baru karena tipe yang diperlukan kompiler 'System.Runtime.CompilerServices.ExtensionAttribute' tidak dapat ditemukan. Apakah Anda kehilangan referensi ke System.Core.dll?

Tetapi saya tidak dapat menemukan System.Core dalam daftar referensi yang tersedia ketika saya mencoba menambahkannya ke proyek. Apa yang harus saya lakukan agar dapat menggunakan metode ekstensi dan mengaktifkan LINQ di proyek saya ?


person Scott Chamberlain    schedule 05.07.2012    source sumber


Jawaban (1)


Metode ekstensi tidak ditambahkan ke .NET hingga versi 3.5. Namun, hal tersebut bukanlah perubahan pada CLR, melainkan perubahan pada kompiler yang menambahkannya, sehingga Anda masih dapat menggunakannya di proyek 2.0 dan 3.0 Anda! Satu-satunya persyaratan adalah Anda harus memiliki kompiler yang dapat membuat 3,5 proyek untuk dapat melakukan solusi ini (Visual Studio 2008 ke atas).

Kesalahan yang Anda dapatkan saat mencoba menggunakan metode ekstensi menyesatkan karena Anda tidak benar-benar memerlukan System.Core.dll untuk menggunakan metode ekstensi. Saat Anda menggunakan metode ekstensi, di belakang layar, kompiler menambahkan [Extension] ke fungsi. Jika Anda memiliki kompiler yang memahami apa yang harus dilakukan dengan atribut [Extension], Anda dapat menggunakannya di proyek 2.0 dan 3.0 jika Anda membuat atribut sendiri.

Cukup tambahkan kelas berikut ke proyek Anda dan Anda kemudian dapat mulai menggunakan metode ekstensi:

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

Blok kode di atas berada di dalam System.Core.Dll, itulah sebabnya kesalahan mengatakan Anda perlu menyertakan file DLL untuk menggunakannya.


Sekarang jika Anda menginginkan fungsionalitas LINQ itu akan membutuhkan sedikit kerja ekstra. Anda perlu menerapkan kembali metode penyuluhan sendiri. Untuk meniru fungsionalitas penuh LINQ ke SQL, kodenya bisa menjadi cukup rumit . Namun, jika Anda hanya menggunakan LINQ to Objects sebagian besar metode LINQ adalah tidak rumit untuk diterapkan. Berikut adalah beberapa fungsi pengganti LINQ ke Objek dari proyek yang saya tulis untuk membantu Anda memulai.

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;
    }
}

Pustaka dengan implementasi ulang penuh LINQ ke Objek dengan ExtensionAttribute yang sudah ditambahkan dapat ditemukan di Proyek LinqBridge (Terima kasih Allon Guralnek).

person Scott Chamberlain    schedule 05.07.2012
comment
Penting untuk diketahui bahwa metode LinqReplacement Anda hanya akan berfungsi untuk Linq to Objects. Ini tidak akan berfungsi untuk Linq to Sql. Sepertinya banyak orang yang tidak menyadari adanya perbedaan. Tapi tetap +1 - person cadrell0; 05.07.2012
comment
Anda tidak perlu menerapkan kembali metode penyuluhan sendiri. Penyedia LINQ-to-Objects yang lengkap telah diimplementasikan kembali untuk .NET 2.0 sejak lama sebagai LinqBridge. Dan itu sudah termasuk ExtensionAttribute yang memungkinkan Anda membuat metode ekstensi di .NET 2.0 dengan VS 2008 ke atas. - person Allon Guralnek; 05.07.2012
comment
@AllonGuralnek Terima kasih atas tautannya, perbarui jawabannya dan berikan kredit kepada Anda. - person Scott Chamberlain; 05.07.2012
comment
@cadrell0 sebagian benar, Anda masih dapat menggunakannya dengan panggilan ke ADO.NET yang melakukan while(reader.Read()) yield BuildObject(reader). Tentu saja, ia akan melakukan segala sesuatu di memori seolah-olah Anda menandai .AsEnumerable() di semua tempat, dan ia akan membaca kolom yang tidak dipedulikannya, tetapi pendekatan seperti itu masih berguna pada hari-hari sebelum Linq. - person Jon Hanna; 04.06.2014