Tanda tangan metode ajaib dalam C #

Saya sajikan untuk perhatian Anda terjemahan artikel The Magical Methods in C # oleh CEZARY PIĄTEK .



Ada satu set khusus tanda tangan metode dalam C # yang memiliki dukungan tingkat bahasa. Metode dengan tanda tangan seperti itu memungkinkan Anda untuk menggunakan sintaks khusus dengan semua kelebihannya. Sebagai contoh, mereka dapat digunakan untuk menyederhanakan kode kami atau membuat DSL untuk mengekspresikan solusi untuk masalah dengan cara yang lebih indah. Saya melihat metode seperti itu di semua tempat, jadi saya memutuskan untuk menulis posting dan merangkum semua temuan saya tentang topik ini, yaitu:



  • Sintaks inisialisasi koleksi
  • Sintaks inisialisasi kamus
  • Dekonstruksi
  • Jenis custom yang dapat ditunggu
  • Pola ekspresi kueri


Sintaks inisialisasi koleksi



Sintaks inisialisasi koleksi sudah cukup lama karena sudah ada sejak C # 3.0 (dirilis akhir 2007). Biarkan saya mengingatkan Anda bahwa sintaks inisialisasi koleksi memungkinkan Anda membuat daftar dengan elemen dalam satu blok:



var list = new List<int> { 1, 2, 3 };


Kode ini setara dengan yang di bawah ini:



var temp = new List<int>();
temp.Add(1);
temp.Add(2);
temp.Add(3);
var list = temp;


BCL. , :



  • IEnumerable
  • void Add(T item)


public class CustomList<T>: IEnumerable
{
    public IEnumerator GetEnumerator() => throw new NotImplementedException();
    public void Add(T item) => throw new NotImplementedException();
}


, Add :



public static class ExistingTypeExtensions
{
    public static void Add<T>(this ExistingType @this, T item) => throw new NotImplementedException();
}


- :



class CustomType
{
    public List<string> CollectionField { get; private set; }  = new List<string>();
}

class Program
{
    static void Main(string[] args)
    {
        var obj = new CustomType
        {
            CollectionField =
            {
                "item1",
                "item2"
            }
        };
    }
}


. ? :



var obj = new CustomType
{
    CollectionField =
    {
        { existingItems }
    }
};


, :



  • IEnumerable
  • void Add(IEnumerable<T> items)


public class CustomList<T>: IEnumerable
{
    public IEnumerator GetEnumerator() => throw new NotImplementedException();
    public void Add(IEnumerable<T> items) => throw new NotImplementedException();
}


, BCL void Add(IEnumerable<T> items), , :



public static class ListExtensions
{
    public static void Add<T>(this List<T> @this, IEnumerable<T> items) => @this.AddRange(items);
}


:



var obj = new CustomType
{
    CollectionField =
    {
        { existingItems.Where(x => /*Filter items*/).Select(x => /*Map items*/) }
    }
};


(IEnumerable):



var obj = new CustomType
{
    CollectionField =
    {
        individualElement1,
        individualElement2,
        { list1.Where(x => /*Filter items*/).Select(x => /*Map items*/) },
        { list2.Where(x => /*Filter items*/).Select(x => /*Map items*/) },
    }
};


.



, -, protobuf. , protobuf: grpctools .NET proto, - :



[DebuggerNonUserCode]
public RepeatableField<ItemType> SomeCollectionField
{
    get
    {
        return this.someCollectionField_;
    }
}


, - , RepeatableField void Add(IEnumerable items), - :



/// <summary>
/// Adds all of the specified values into this collection. This method is present to
/// allow repeated fields to be constructed from queries within collection initializers.
/// Within non-collection-initializer code, consider using the equivalent <see cref="AddRange"/>
/// method instead for clarity.
/// </summary>
/// <param name="values">The values to add to this collection.</param>
public void Add(IEnumerable<T> values)
{
    AddRange(values);
}




C# 6.0 — , . :



var errorCodes = new Dictionary<int, string>
{
    [404] = "Page not Found",
    [302] = "Page moved, but left a forwarding address.",
    [500] = "The web server can't come out to play today."
};


:



var errorCodes = new Dictionary<int, string>();
errorCodes[404] = "Page not Found";
errorCodes[302] = "Page moved, but left a forwarding address.";
errorCodes[500] = "The web server can't come out to play today.";


, .



— , Dictionary<T> , :



class HttpHeaders
{
    public string this[string key]
    {
        get => throw new NotImplementedException();
        set => throw new NotImplementedException();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var headers = new HttpHeaders
        {
            ["access-control-allow-origin"] = "*",
            ["cache-control"] = "max-age=315360000, public, immutable"
        };
    }
}




C# 7.0 . :



var point = (5, 7);
// decomposing tuple into separated variables
var (x, y) = point;


:



ValueTuple<int, int> point = new ValueTuple<int, int>(1, 4);
int x = point.Item1;
int y = point.Item2;


:



int x = 5, y = 7;
//switch
(x, y) = (y,x);


:



class Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y)  => (X, Y) = (x, y);
}


, . , :



  • Deconstruct
  • void
  • out


Point :



class Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y) => (X, Y) = (x, y);

    public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);
}


:



var point = new Point(2, 4);
var (x, y) = point;


" " :



int x;
int y;
new Point(2, 4).Deconstruct(out x, out y);


:



public static class PointExtensions
{
     public static void Deconstruct(this Point @this, out int x, out int y) => (x, y) = (@this.X, @this.Y);
}


KeyValuePair<TKey, TValue>, :



foreach (var (key, value) in new Dictionary<int, string> { [1] = "val1", [2] = "val2" })
{
    //TODO: Do something
}


KeyValuePair<TKey, TValue>.Deconstruct(TKey, TValue) netstandard2.1. netstandard .



awaitable



C# 5.0 ( Visual Studio 2012) async/await, . , :



void DoSomething()
{
    DoSomethingAsync().ContinueWith((task1) => {
        if (task1.IsCompletedSuccessfully)
        {
            DoSomethingElse1Async(task1.Result).ContinueWith((task2) => {
                if (task2.IsCompletedSuccessfully)
                {
                    DoSomethingElse2Async(task2.Result).ContinueWith((task3) => {
                        //TODO: Do something
                    });
                }
            });
        }
    });
}

private Task<int> DoSomethingAsync() => throw new NotImplementedException();
private Task<int> DoSomethingElse1Async(int i) => throw new NotImplementedException();
private Task<int> DoSomethingElse2Async(int i) => throw new NotImplementedException();


async/await:



async Task DoSomething()
{
    var res1 = await DoSomethingAsync();
    var res2 = await DoSomethingElse1Async(res1);
    await DoSomethingElse2Async(res2);
}


, await Task. , GetAwaiter, :



  • System.Runtime.CompilerServices.INotifyCompletion void OnCompleted(Action continuation)
  • IsCompleted
  • GetResult


await GetAwaiter, TaskAwaiter<TResult> , :



class CustomAwaitable
{
    public CustomAwaiter GetAwaiter() => throw new NotImplementedException();
}

class CustomAwaiter: INotifyCompletion
{
    public void OnCompleted(Action continuation) => throw new NotImplementedException();

    public bool IsCompleted => throw new NotImplementedException();

    public void GetResult() => throw new NotImplementedException();
}


: " await awaitable ?". , Stephen Toub "await anything", .



query expression



C# 3.0 — Language-Integrated Query, LINQ, SQL- . LINQ : SQL- . , . . , . LINQ , SQL- , . . C#, CLR. LINQ IEnumerable, IEnumerable<T> IQuerable<T>, , , query expression. , LINQ, :



class C
{
    public C<T> Cast<T>();
}

class C<T> : C
{
    public C<T> Where(Func<T,bool> predicate);

    public C<U> Select<U>(Func<T,U> selector);

    public C<V> SelectMany<U,V>(Func<T,C<U>> selector, Func<T,U,V> resultSelector);

    public C<V> Join<U,K,V>(C<U> inner, Func<T,K> outerKeySelector, Func<U,K> innerKeySelector, Func<T,U,V> resultSelector);

    public C<V> GroupJoin<U,K,V>(C<U> inner, Func<T,K> outerKeySelector, Func<U,K> innerKeySelector, Func<T,C<U>,V> resultSelector);

    public O<T> OrderBy<K>(Func<T,K> keySelector);

    public O<T> OrderByDescending<K>(Func<T,K> keySelector);

    public C<G<K,T>> GroupBy<K>(Func<T,K> keySelector);

    public C<G<K,E>> GroupBy<K,E>(Func<T,K> keySelector, Func<T,E> elementSelector);
}

class O<T> : C<T>
{
    public O<T> ThenBy<K>(Func<T,K> keySelector);

    public O<T> ThenByDescending<K>(Func<T,K> keySelector);
}

class G<K,T> : C<T>
{
    public K Key { get; }
}


, , LINQ . LINQ . , , Understand monads with LINQ Miłosz Piechocki.





Tujuan artikel ini bukan untuk meyakinkan Anda untuk menyalahgunakan trik sintaksis ini, tetapi untuk membuatnya lebih dimengerti. Di sisi lain, mereka tidak selalu dapat dihindari. Mereka dirancang untuk digunakan, dan kadang-kadang mereka dapat membuat kode Anda lebih baik. Jika Anda takut kode yang dihasilkan tidak akan dapat dipahami oleh kolega Anda, Anda perlu menemukan cara untuk membagikan pengetahuan Anda dengan mereka (atau setidaknya tautan ke artikel ini). Saya tidak yakin apakah ini satu set lengkap "metode ajaib", jadi jika Anda tahu lagi - silakan berbagi di komentar.




All Articles