我要向你的翻译C#中的妙用方法通过CEZARYPIĄTEK。
C#中有一组特定的方法签名,这些签名具有语言支持。具有此类签名的方法可让您使用自定义语法,并具有所有优点。例如,它们可以用于简化我们的代码或创建DSL,以便以更美观的方式表示问题的解决方案。我到处都遇到这样的方法,因此我决定写一篇文章,总结关于该主题的所有发现,即:
集合初始化语法
集合初始化语法相当古老,因为它自C#3.0(2007年末发布)以来就已经存在。让我提醒您,集合初始化语法允许您创建一个在一个块中包含元素的列表:
var list = new List<int> { 1, 2, 3 };
此代码等效于以下代码:
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);
}
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.
本文的目的并不是要说服您滥用这些语法技巧,而是要使它们更清楚。另一方面,不能总是避免它们。它们被设计为可以使用,有时它们可以使您的代码更好。如果您担心产生的代码对您的同事来说是难以理解的,那么您需要找到一种与他们共享知识的方法(或者至少是本文的链接)。我不确定这是否是此类“魔术方法”的完整集合,因此,如果您知道更多信息,请在评论中分享。