С# на С#, удобные функции языка
Я хотел бы узнать, какие все удобные функции С# и как они отображаются на С#.
Например, автоматические свойства:
public string Foo { get; set; }
... отображает примерно следующее:
string <Foo>k__BackingField;
[CompilerGenerated]
public string Foo {
get { return this.<Foo>k__BackingField; }
set { this.<Foo>k__BackingField = value; }
}
Циклы forach:
foreach(char c in "Hello") {
Console.WriteLine(c);
}
... отображает что-то вроде этого (я думаю):
CharEnumerator en;
try {
en = "Hello".GetEnumerator();
while (en.MoveNext()) {
char c = en.Current;
Console.WriteLine(c);
}
} finally {
IDisposable disp = en as IDisposable;
if (disp != null)
disp.Dispose();
}
Утилизация счетчика делает foreach
очень полезным при работе с неуправляемыми ресурсами, такими как циклическое перемещение строк в файле или записи в базе данных.
Я думаю, что хорошее понимание этих функций высокого уровня может помочь нам написать лучший код. Каковы другие удобные функции С# и как они отображаются на С#?
Ответы
Ответ 1
Если вы хотите поговорить о количестве сохраненного кода, самыми большими вкладчиками (IMO) являются:
блоки итератора
Пример:
public static IEnumerable<int> Get() {yield return 1; yield return 2;}
Сохраненный:
- запись реализации
IEnumerable<T>
- запись
IEnumerator<T>
реализации
- состояние обработки перечислителя; вы видели, насколько это ужасно? Серьезно.
захваченные переменные (методы anon/lambdas)
Пример:
var list2 = list1.FindAll(x => (x.Value % 10) == find);
Сохраненный:
- запись класса для хранения состояния
- в сложных случаях, вложенное состояние
- инициализация оболочки состояния
- запись метода в этот класс
Компилятор lambda выражения
Пример (сверху):
Expression<Func<Foo,bool>> pred = x => (x.Value % 10) == find;
Сохраненный:
- yeuch - много кода дерева; очень, очень сложный; в приведенном выше примере я могу видеть (в определенном порядке)
Expression.Parameter
, Expression.Property
, Expression.Field
, Expression.Constant
, Expression.Equal
, Expression.Modulo
, Expression.Lambda
... объединить; -p
Ответ 2
использование синтаксиса
using(x)
{
...
}
Карты в
try {
// Code
}
finally
{
if(x != null)
((IDisposable)x).Dispose();
}
В LINQ используется синтаксический сахар
from x in l where y select z;
переводится на
l.Where(x => y).Select(x => z);
Ответ 3
LINQ в целом (особенно с использованием синтаксиса запроса LINQ) по существу является основным С#/.NET которая часто заменяет for-loop/iterators/сложную логику запросов.
Ответ 4
Ответ 5
Оператор?:, который проверяет логическое или логическое выражение и возвращает первое значение, если тест возвращает true
, а второй значение, если тест возвращает false
:
condition ? first_expression : second_expression
Что по существу означает:
var x;
if (condition)
{
x = first_expression;
}
else
{
x = second_expression
}
Используя оператор?: вы можете написать int x = condition ? 10 : 20;
вместо того, чтобы записывать весь оператор if
.
Ответ 6
Инициализаторы объектов - довольно синтаксический сахар:
public class Book
{
public string Author { get; set; }
public string Title { get; set; }
}
Book book = new Book() {Author = "John Smith", Title = "C# Syntax"};
Вышеупомянутый - это еще один способ написать:
Book book = new Book();
book.Author = "John Smith";
book.Title = "C# Syntax";
Неявные типы:
var book = new Book() {Author = "John Smith", Title = "C# Syntax"};
Ответ 7
Оператор null coalescing (??) может быть довольно изящным. Это...
ISomeRef myRef = firstChoice ?? secondChoice ?? fallback;
Переводит на что-то функциональное, эквивалентное:
ISomeRef myRef = firstChoice;
if(myRef == null) myRef = secondChoice;
if(myRef == null) myRef = fallback;
Я говорю функционально эквивалентно, потому что я еще не смотрел в отражатель:)
Ответ 8
Анонимные типы:
var message = new { Message = "Hello, world!", MessageID = 1 };
переводится на
<>f__AnonymousType0<string, int> message =
new <>f__AnonymousType0<string, int>("Hello, world!", 1);
где
[CompilerGenerated]
[DebuggerDisplay(
@"\{ Message = {Message},
MessageID = {MessageID} }",
Type="<Anonymous Type>"
)
]
internal sealed class <>f__AnonymousType0<
<Message>j__TPar,
<MessageID>j__TPar
> {
// Fields
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly <Message>j__TPar <Message>i__Field;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly <MessageID>j__TPar <MessageID>i__Field;
// Methods
[DebuggerHidden]
public <>f__AnonymousType0(
<Message>j__TPar Message,
<MessageID>j__TPar MessageID
) {
this.<Message>i__Field = Message;
this.<MessageID>i__Field = MessageID;
}
[DebuggerHidden]
public override bool Equals(object value) {
var type = value as <>f__AnonymousType0<
<Message>j__TPar,
<MessageID>j__TPar
>;
return (((type != null) &&
EqualityComparer<<Message>j__TPar>.Default.Equals(
this.<Message>i__Field,
type.<Message>i__Field)
) &&
EqualityComparer<<MessageID>j__TPar>.Default.Equals(
this.<MessageID>i__Field,
type.<MessageID>i__Field)
);
}
[DebuggerHidden]
public override int GetHashCode() {
int num = 0x2e22c70c;
num = (-1521134295 * num) +
EqualityComparer<<Message>j__TPar>.Default.GetHashCode(
this.<Message>i__Field
);
return ((-1521134295 * num) +
EqualityComparer<<MessageID>j__TPar>.Default.GetHashCode(
this.<MessageID>i__Field)
);
}
[DebuggerHidden]
public override string ToString() {
StringBuilder builder = new StringBuilder();
builder.Append("{ Message = ");
builder.Append(this.<Message>i__Field);
builder.Append(", MessageID = ");
builder.Append(this.<MessageID>i__Field);
builder.Append(" }");
return builder.ToString();
}
// Properties
public <Message>j__TPar Message {
get {
return this.<Message>i__Field;
}
}
public <MessageID>j__TPar MessageID {
get {
return this.<MessageID>i__Field;
}
}
}
Ответ 9
Анонимные делегаты меняются в методы во время компиляции, поэтому это:
var collection = new[] { 1, 2, 3, 4 }.Where(i => i == 2);
вызывает создание нового метода:
[CompilerGenerated]
private static bool <Main>b__0(int i)
{
return (i == 2);
}
и изменяется на:
IEnumerable<int> collection = new int[] { 1, 2, 3, 4 }.Where<int>(<Main>b__0);
Обратите внимание, что оно использует имя метода, которое невозможно создать перед компиляцией <Main>b__0
- вы не можете иметь <>
в имени метода, поэтому всегда избегайте столкновений.
То же самое происходит с этим, а также i => i == 2
:
delegate(int i) { return i == 2; }
Вы также заметите, что вы можете использовать короткую руку для:
new[] { 1, 2, 3, 4 }
// goes to...
new int[] { 1, 2, 3, 4 }
и
var foo = new Foo();
// goes to...
Foo foo = new Foo();
Ответ 10
Другими примерами являются лямбда-выражения.
var myZombies = myMonsters.Where(monster => monster.Kind == MonsterKind.Zombie);
выталкивает делегата Lambda в свой собственный метод со странным именем.
Вы можете использовать Reflector и переключаться между версиями С# в диалоге параметров, чтобы увидеть различия в том, как такие вещи будут устранены.
Ответ 11
Nullable<T>
- еще одно невероятное удобство. Особенно удобно использовать синтаксис ?
, как в int?
для Nullable<int>
.
Ответ 12
Методы расширения.
Если это ваш метод расширения:
static class ObjectExtensions
{
public void ExtensionMethod(this object obj)
{
// Do something here...
}
}
И вы вызываете obj.ExtensionMethod()
Это означает:
ObjectExtensions.ExtensionMethod(obj)
Если у вас есть версия компилятора С#, которая поддерживает методы расширения, вы можете обмануть компилятор, чтобы позволить вам использовать методы расширения в версиях .Net до 3.5, создав System.Runtime.CompilerServices.ExtensionAttribute
, например: (It совершенно безопасен для этого, поскольку компилятор сопоставляет методы расширения в стандартный IL)
namespace System.Runtime.CompilerServices
{
using System;
internal sealed class ExtensionAttribute : Attribute
{
}
}
Ответ 13
Необычный среди языков высокого уровня, С# имеет оператор 'goto', и, следовательно, несколько других операторов С# могут рассматриваться как языковые переводы в оператор goto.
Например, оператор if() напрямую ссылается на goto, тогда как стандартный цикл for() фактически сопоставляет цикл while(), который сопоставляется с goto.
Оператор switch() необычен, поскольку он скомпилирован по-разному в зависимости от количества случаев и типа аргумента switch. Таким образом, невозможно рассматривать это преобразование языка в goto.
Ответ 14
Инициализаторы коллекции (и вывод типа):
var scoobies = new List<Scooby>()
{
new Scooby("Buffy"),
new Scooby("Willow"),
new Scooby("Xander")
};
Карты в:
List<Scooby>() scoobies = new List<Scooby>();
scoobies.Add(new Scooby("Buffy"));
scoobies.Add(new Scooby("Willow"));
scoobies.Add(new Scooby("Xander"));