Signatures de méthode magique en C #

Je prĂ©sente Ă  votre attention la traduction de l'article Les mĂ©thodes magiques en C # de CEZARY PIĄTEK .



Il existe un ensemble spĂ©cifique de signatures de mĂ©thode en C # qui prennent en charge le langage. Les mĂ©thodes avec de telles signatures permettent l'utilisation d'une syntaxe spĂ©ciale avec tous ses avantages. Par exemple, ils peuvent ĂȘtre utilisĂ©s pour simplifier notre code ou crĂ©er un DSL afin d'exprimer une solution Ă  un problĂšme d'une maniĂšre plus belle. Je vois de telles mĂ©thodes partout, j'ai donc dĂ©cidĂ© d'Ă©crire un article et de rĂ©sumer toutes mes conclusions sur ce sujet, Ă  savoir:



  • Syntaxe d'initialisation de la collection
  • Syntaxe d'initialisation du dictionnaire
  • DĂ©constructeurs
  • Types attendus personnalisĂ©s
  • Le modĂšle d'expression de requĂȘte


Syntaxe d'initialisation de la collection



La syntaxe d'initialisation de la collection est assez ancienne puisqu'elle existe depuis C # 3.0 (sortie fin 2007). Permettez-moi de vous rappeler que la syntaxe d'initialisation de la collection vous permet de créer une liste avec des éléments dans un bloc:



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


Ce code est Ă©quivalent Ă  celui ci-dessous:



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.





Le but de cet article n'est pas du tout de vous convaincre d'abuser de ces astuces syntaxiques, mais de les rendre plus claires. D'un autre cĂŽtĂ©, ils ne peuvent pas toujours ĂȘtre Ă©vitĂ©s. Ils ont Ă©tĂ© conçus pour ĂȘtre utilisĂ©s et peuvent parfois amĂ©liorer votre code. Si vous craignez que le code qui en rĂ©sulte ne soit incomprĂ©hensible pour vos collĂšgues, vous devez trouver un moyen de partager vos connaissances avec eux (ou au moins un lien vers cet article). Je ne suis pas sĂ»r qu’il s’agisse d’un ensemble complet de ces «mĂ©thodes magiques», donc si vous en savez plus, veuillez les partager dans les commentaires.




All Articles