Скрытые возможности C #? [закрыто]

Object.keys () Метод Object.keys () возвращает массив собственных перечислимых свойств данного объекта в том же порядке, что и для цикла for ... in (разница заключается в том, что for-in loop также перечисляет свойства в цепочке прототипов).

var arr1 = Object.keys(obj);

Object.values ​​() Метод Object.values ​​() возвращает массив собственных значений перечислимого свойства данного объекта в том же порядке, что и что обеспечивается циклом for for ... in (разница заключается в том, что цикл for-in также перечисляет свойства в цепочке прототипов).

var arr2 = Object.values(obj);

Для получения дополнительной информации см. здесь

1476
задан 56 revs, 31 users 10% 25 September 2017 в 20:53
поделиться

295 ответов

" урожай " поступил бы по моему мнению. Некоторые атрибуты как [DefaultValue ()] также среди моего избранного.

" var" ключевое слово немного более известен, но что можно использовать его в.NET 2,0 приложения также (как долго, поскольку Вы используете.NET 3,5 компилятора и устанавливаете его для вывода 2,0 кодов), кажется, не известен очень хорошо.

Редактирование: kokos, благодарит указать?? оператор, это действительно действительно полезно. Так как это немного трудно к Google для него (как?? просто проигнорирован), вот страница документации MSDN для того оператора: ?? Оператор (Ссылка C#)

209
ответ дан 4 revs, 2 users 80% 25 September 2017 в 20:53
поделиться

Не уверен, упоминался ли этот вопрос, но атрибут ThreadStatic действительно полезен. Это делает статическое поле статическим только для текущего потока.

[ThreadStatic]
private static int _ThreadStaticInteger;

Вы не должны включать инициализатор, потому что он выполняется только один раз для всего приложения, лучше сделать поле обнуляемым и проверить, является ли значение нулевым, прежде чем использовать его.

И еще одна вещь для потоков приложений ASP.NET используется повторно, так что если вы измените значение, оно может в конечном итоге использоваться для другого запроса страницы.

Тем не менее я нашел это полезным в нескольких случаях. Например, при создании пользовательского класса транзакции, который:

using (DbTransaction tran = new DbTransaction())
{
    DoQuery("...");
    DoQuery("...");    
}

Конструктор DbTransaction устанавливает поле ThreadStatic на свое собственное значение и сбрасывает его на ноль в методе dispose. DoQuery проверяет статическое поле и, если! = Null, использует текущую транзакцию, если нет, то по умолчанию используется что-то другое. Мы избегаем необходимости передавать транзакцию каждому методу, и это облегчает перенос других методов, которые изначально не предназначались для использования с транзакцией внутри транзакции ...

Только одно использование:)

10
ответ дан 2 revs, 2 users 86% 25 September 2017 в 20:53
поделиться

Я думаю, что одна из большинства недооцениваемых и менее известных функций C# (.NET 3.5) Деревья выражений , особенно , когда объединено с Дженериками и Лямбдами. Это - подход к созданию API, которое используют более новые библиотеки как NInject и Moq.

, Например, скажем, что я хочу зарегистрировать метод в API и что API должен получить имя метода

, Учитывая этот класс:

public class MyClass
{
     public void SomeMethod() { /* Do Something */ }
}

Прежде, было очень распространено видеть, что разработчики делают это со строками и типами (или что-то еще в основном основанное на операция со строками):

RegisterMethod(typeof(MyClass), "SomeMethod");

ну, который сосет из-за отсутствия строгого контроля типов. Что, если я переименовываю "SomeMethod"? Теперь, в 3,5 однако, я могу сделать это способом со строгим контролем типов:

RegisterMethod<MyClass>(cl => cl.SomeMethod());

, В котором класс RegisterMethod использует Expression<Action<T>> как это:

void RegisterMethod<T>(Expression<Action<T>> action) where T : class
{
    var expression = (action.Body as MethodCallExpression);

    if (expression != null)
    {
        // TODO: Register method
        Console.WriteLine(expression.Method.Name);
    }
}

Это - одна большая причина, что я люблю Лямбды и Деревья выражений прямо сейчас.

220
ответ дан 4 revs, 4 users 91% 25 September 2017 в 20:53
поделиться

ОТЛАДКА #if директива препроцессору. Это Полезно для тестирования и отладки (хотя я обычно предпочитаю идти путем поблочного тестирования).

string customerName = null;
#if DEBUG
  customerName = "Bob"
#endif

Это только выполнит блок кода, если Visual Studio будет установлена скомпилировать в режиме 'Debug'. Иначе блок кода будет проигнорирован компилятором (и grayed в Visual Studio).

25
ответ дан 4 revs, 4 users 47% 25 September 2017 в 20:53
поделиться

Мой любимый прием использует , пустой указатель объединяет оператор и круглые скобки, чтобы автоволшебно инстанцировать наборов для меня.

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }
409
ответ дан 6 revs, 3 users 56% 25 September 2017 в 20:53
поделиться
  • 1
    Терминальные приложения can' t получают доступ к системному буферу обмена. Взлом isn' t настолько плохо, хотя, я действительно использую pbcopy в других контекстах. – event_jr 4 April 2012 в 12:41

Я называю этот AutoDebug, потому что можно бросить прямо в отладку, где и когда Вам нужно на основе значения bool, которое могло также быть сохранено как пользователь проекта, устанавливающий также.

Пример:

//Place at top of your code
public UseAutoDebug = true;


//Place anywhere in your code including catch areas in try/catch blocks
Debug.Assert(!this.UseAutoDebug);

Просто вышеупомянутое места в блоках попытки/выгоды или других областях Вашего кода и набора UseAutoDebug к TRUE или FALSE и заскакивают в отладку каждый раз, когда Вы желаете тестирования.

можно оставить этот код на месте и переключить эту функцию на и прочь при тестировании, можно также сохранить его как Установку Проекта, и вручную изменить его после развертывания для получения дополнительной информации ошибки от пользователей когда/в случае необходимости также.

Вы видите функциональный и рабочий пример использования этой техники в этой Visual Studio Шаблон Проекта C# здесь, где это используется в большой степени:

http://code.msdn.microsoft.com/SEHE

6
ответ дан 2 revsTheUberOverLord 25 September 2017 в 20:53
поделиться

Система. Время выполнения. Дистанционная работа. Прокси. RealProxy

, который Это включает Аспектно-ориентированному программированию в C#, и можно также сделать много другого необычного материала с ним.

5
ответ дан Thomas Danecker 25 September 2017 в 20:53
поделиться
  • 1
    Я действительно просто пробовал его, и это работало на меня. Он возможный, что Ваши viewController выходы являются not' t набор правильно? Могло бы стоить зарегистрироваться в отладчике. – Mark Bessey 3 July 2009 в 17:55

Я сказал бы, что использование определенных системных классов для дополнительных методов очень удобно, например, Система. Перечисление, можно сделать что-то как ниже...

[Flags]
public enum ErrorTypes : int {
    None = 0,
    MissingPassword = 1,
    MissingUsername = 2,
    PasswordIncorrect = 4
}

public static class EnumExtensions {

    public static T Append<T> (this System.Enum type, T value) where T : struct
    {
        return (T)(ValueType)(((int)(ValueType) type | (int)(ValueType) value));
    }

    public static T Remove<T> (this System.Enum type, T value) where T : struct
    {
        return (T)(ValueType)(((int)(ValueType)type & ~(int)(ValueType)value));
    }

    public static bool Has<T> (this System.Enum type, T value) where T : struct
    {
        return (((int)(ValueType)type & (int)(ValueType)value) == (int)(ValueType)value);
    }

}

...

//used like the following...

ErrorTypes error = ErrorTypes.None;
error = error.Append(ErrorTypes.MissingUsername);
error = error.Append(ErrorTypes.MissingPassword);
error = error.Remove(ErrorTypes.MissingUsername);

//then you can check using other methods
if (error.Has(ErrorTypes.MissingUsername)) {
    ...
}

Это - просто пример, конечно - методы могли использовать немного больше работы...

38
ответ дан 2 revs, 2 users 88% 25 September 2017 в 20:53
поделиться
  • 1
    @alliswell опция времени проектирования doesn' t работа, по сравнению с поворотами это в \\r \\n – Renae 8 October 2013 в 06:11

Этот не "скрыт" так, поскольку это неверно называется.

Большое внимание обращено на алгоритмы "карта", "уменьшите", и "фильтр". То, что не понимает большинство людей, - то, что.NET 3.5 добавила все три из этих алгоритмов, но она дала им очень имена выхода SQL, на основе того, что они - часть LINQ.

"карта" => Выбор
Преобразовывает данные из одной формы в другой

, "уменьшают" =>, Агрегат
Агрегировал значения в единственный результат

"фильтр" =>, Где
данные Фильтров на основе критерии

способность использовать LINQ, чтобы сделать встроенная работа над наборами, которые раньше брали повторение и условные выражения, может быть невероятно ценной. Стоит изучить, как все дополнительные методы LINQ могут помочь сделать Ваш код намного более компактным и удобным в сопровождении.

117
ответ дан Brad Wilson 25 September 2017 в 20:53
поделиться
  • 1
    Большой ответ, спасибо. Вы упоминаете порядок индекса: Будет упомянутый индекс работать хорошо оба на " ГДЕ LastName = ' a' ORDER BY FirstName" и для " ГДЕ FirstName = ' a' ORDER BY LastName"? – Niels Brinch 29 March 2011 в 04:40

C# 3.0's понимания запроса LINQ являются полноценными одноместными пониманиями а-ля Haskell (на самом деле, они были разработаны одним из разработчиков Haskell). Они будут работать на любой универсальный тип, который следует за "шаблоном LINQ" и позволяет Вам писать в чистом одноместном функциональном стиле, что означает, что все Ваши переменные неизменны (как будто единственные переменные, которые Вы использовали, были IDisposable с и IEnumerable с в использование и foreach операторы). Это полезно для хранения объявлений переменной близко к тому, где они используются и удостоверяясь, что все побочные эффекты явно объявляются, если существует кто-либо вообще.

 interface IFoo<T>
  { T Bar {get;}
  }

 class MyFoo<T> : IFoo<T> 
  { public MyFoo(T t) {Bar = t;}
    public T Bar {get; private set;} 
  }

 static class Foo 
  { public static IFoo<T> ToFoo<T>(this T t) {return new MyFoo<T>(t);}

    public static void Do<T>(this T t, Action<T> a) { a(t);}

    public static IFoo<U> Select<T,U>(this IFoo<T> foo, Func<T,U> f) 
     { return f(foo.Bar).ToFoo();
     }
  }

 /* ... */

 using (var file = File.OpenRead("objc.h"))
 { var x = from f in file.ToFoo()
           let s = new Scanner(f)
           let p = new Parser {scanner = s}
           select p.Parse();

   x.Do(p => 
    { /* drop into imperative code to handle file 
         in Foo monad if necessary */      
    });

 }
19
ответ дан Mark Cidade 25 September 2017 в 20:53
поделиться
  • 1
    Неполный. Имена тега и названия атрибута нечувствительны к регистру, в то время как значения атрибута чувствительны к регистру. – powerboy 3 October 2011 в 23:10

Закрытия

, Так как анонимные делегаты были добавлены к 2,0, мы были в состоянии разработать закрытия. Они редко используются программистами, но предоставляют большие преимущества, такие как непосредственное повторное использование кода. Рассмотрите эту часть кода:

bool changed = false;

if (model.Prop1 != prop1)
{
    changed = true;
    model.Prop1 = prop1;
}
if (model.Prop2 != prop2)
{
    changed = true;
    model.Prop2 = prop2;
}
// ... etc. 

Примечание, что операторы "if" выше выполняют подобные части кода за исключением одной строки кода, т.е. установку различных свойств. Это может быть сокращено со следующим, где переменная строка кода вводится в качестве параметра в Action объект, соответственно названный setAndTagChanged:

bool changed = false;
Action<Action> setAndTagChanged = (action) => 
{ 
    changed = true; 
    action(); 
};

if (model.Prop1 != prop1) setAndTagChanged(() => model.Prop1 = prop1);
if (model.Prop2 != prop2) setAndTagChanged(() => model.Prop2 = prop2);

Во втором случае, закрытие позволяет Вам определять объем change переменная в Вашей лямбде, которая является кратким способом приблизиться к этой проблеме.

альтернативный путь состоит в том, чтобы использовать другую неиспользованную функцию, "или равный" двоичный оператор присваивания. Следующий код показывает как:

private bool conditionalSet(bool condition, Action action)
{
    if (condition) action();
    return condition;
}

// ...

bool changed = false;
changed |= conditionalSet(model.Prop1 == prop1, () => model.Prop1 = prop1);
changed |= conditionalSet(model.Prop2 == prop2, () => model.Prop2 = prop2);
38
ответ дан 3 revs, 3 users 80% 25 September 2017 в 20:53
поделиться

Другие недогруженные операторы checked и unchecked:

short x = 32767;   // 32767 is the max value for short
short y = 32767;
int z1 =  checked((short)(x + y));   //will throw an OverflowException
int z2 =  unchecked((short)(x + y)); // will return -2
int z3 =  (short)(x + y);            // will return -2
55
ответ дан 2 revs, 2 users 89% 25 September 2017 в 20:53
поделиться

Метод TrueForAll List<T>:

List<int> s = new List<int> { 6, 1, 2 };

bool a = s.TrueForAll(p => p > 0);
10
ответ дан Moran Helman 25 September 2017 в 20:53
поделиться
  • 1
    Действительно? Я думал, что это было удержано от использования столько, сколько первый ANSI C спецификация... – fge 6 January 2012 в 19:15

Существуют операторы для выполнения implicit и explicit пользовательское преобразование типов между заявленным классом и одним или несколькими произвольными классами. implicit оператор эффективно позволяет моделирование перегрузки assignement оператора, который возможен на языках, таких как C++, но не C#.

Это, кажется, не функция, через которую каждый приезжает очень часто, но это на самом деле используется в LINQ к библиотеке XML (System.Xml.Linq), где можно неявно преобразовать строки в XName объекты. Пример:

XName tagName = "x:Name";

я обнаружил эту функцию в этом статья о том, как моделировать множественное наследование в C#.

11
ответ дан 4 revs, 4 users 46% 25 September 2017 в 20:53
поделиться

У Вас могут быть общие методы в неуниверсальном классе.

7
ответ дан JohnOpincar 25 September 2017 в 20:53
поделиться

Прохладный прием для эмуляции функциональных "подстановочных" аргументов (как '_' в Haskell) при использовании лямбд:

(_, b, __) => b.DoStuff();  // only interested in b here
7
ответ дан 2 revs, 2 users 91% 26 September 2017 в 06:53
поделиться

Только для ссылки - перечислимые бинарные операции с помощью дополнительного метода.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace BinaryOpGenericTest
{
    [Flags]
    enum MyFlags
    {
        A = 1,
        B = 2,
        C = 4

    }

    static class EnumExtensions
    {
        private static Dictionary<Type, Delegate> m_operations = new Dictionary<Type, Delegate>();

        public static bool IsFlagSet<T>(this T firstOperand, T secondOperand) 
                                                  where T : struct
        {

            Type enumType = typeof(T);


            if (!enumType.IsEnum)
            {
                throw new InvalidOperationException("Enum type parameter required");
            }


            Delegate funcImplementorBase = null;
            m_operations.TryGetValue(enumType, out funcImplementorBase);

            Func<T, T, bool> funcImplementor = funcImplementorBase as Func<T, T, bool>;

            if (funcImplementor == null)
            {
                funcImplementor = buildFuncImplementor(secondOperand);
            }



            return funcImplementor(firstOperand, secondOperand);
        }


        private static Func<T, T, bool> buildFuncImplementor<T>(T val)
                                                            where T : struct
        {
            var first = Expression.Parameter(val.GetType(), "first");
            var second = Expression.Parameter(val.GetType(), "second");

            Expression convertSecondExpresion = Expression.Convert(second, typeof(int));
            var andOperator = Expression.Lambda<Func<T, T, bool>>(Expression.Equal(
                                                                                                       Expression.And(
                                                                                                            Expression.Convert(first, typeof(int)),
                                                                                                             convertSecondExpresion),
                                                                                                       convertSecondExpresion),
                                                                                             new[] { first, second });
            Func<T, T, bool> andOperatorFunc = andOperator.Compile();
            m_operations[typeof(T)] = andOperatorFunc;
            return andOperatorFunc;
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            MyFlags flag = MyFlags.A | MyFlags.B;

            Console.WriteLine(flag.IsFlagSet(MyFlags.A));            
            Console.WriteLine(EnumExtensions.IsFlagSet(flag, MyFlags.C));
            Console.ReadLine();
        }
    }
}
3
ответ дан 2 revs, 2 users 74%Rene Stein 26 September 2017 в 06:53
поделиться

Группы метода не известны.

Данный:

Func<Func<int,int>,int,int> myFunc1 = (i, j) => i(j);
Func<int, int> myFunc2 = i => i + 2;

можно сделать это:

var x = myFunc1(myFunc2, 1);

вместо этого:

var x = myFunc1(z => myFunc2(z), 1);
6
ответ дан Jonathan Parker 26 September 2017 в 06:53
поделиться

Цепочка конструктора уже цитируется?

namespace constructorChain {
    using System;

    public class Class1 {
        public string x;
        public string y;

        public Class1() {
            x = "class1";
            y = "";
        }

        public Class1(string y)
            : this() {
            this.y = y;
        }
    }

    public class Class2 : Class1 {
        public Class2(int y)
            : base(y.ToString()) {

        }
    }
}

...

        constructorChain.Class1 c1 = new constructorChain.Class1();
        constructorChain.Class1 c12 = new constructorChain.Class1("Hello, Constructor!");
        constructorChain.Class2 c2 = new constructorChain.Class2(10);
        Console.WriteLine("{0}:{1}", c1.x, c1.y);
        Console.WriteLine("{0}:{1}", c12.x, c12.y);
        Console.WriteLine("{0}:{1}", c2.x, c2.y);

        Console.ReadLine();
5
ответ дан kentaromiura 26 September 2017 в 06:53
поделиться
  • 1
    @KennyTM: Конечно, фиксированный. Спасибо. @Piet Delport: Это hadn' t произошел со мной. @sdcvvc: +1:) – Thomas 4 October 2010 в 11:21

Можно использовать дженерики для проверки (время компиляции), если аргумент метода реализует два интерфейса:

interface IPropA 
{
    string PropA { get; set; } 
}

interface IPropB 
{
    string PropB { get; set; }
}

class TestClass 
{
    void DoSomething<T>(T t) where T : IPropA, IPropB 
    {
        MessageBox.Show(t.PropA);
        MessageBox.Show(t.PropB);
    }
}

То же с аргументом, который наследован от базового класса и интерфейса.

12
ответ дан tuinstoel 26 September 2017 в 06:53
поделиться

One thing not many people know about are some of the C#-introduced preprocessor directives. You can use #error This is an error. to generate a compiler error and #warning This is a warning.

I usually use these when I'm developing with a top-down approach as a "todo" list. I'll #error Implement this function, or #warning Eventually implement this corner case as a reminder.

10
ответ дан 3 October 2019 в 21:34
поделиться

FlagsAttribute, небольшая, но приятная функция при использовании перечисления для создания битовых масок:

[Flags]
public enum ConfigOptions
{
    None    = 0,
    A       = 1 << 0,
    B       = 1 << 1,
    Both    = A | B
}

Console.WriteLine( ConfigOptions.A.ToString() );
Console.WriteLine( ConfigOptions.Both.ToString() );
// Will print:
// A
// A, B
13
ответ дан 3 October 2019 в 21:34
поделиться

Методы расширения могут быть вызваны на null ; это не вызовет выброса NullReferenceException .

Пример приложения: вы можете определить альтернативу для ToString () под названием ToStringOrEmpty () , которая вернет пустая строка при вызове null .

11
ответ дан 3 October 2019 в 21:34
поделиться

Вложенные классы могут получить доступ к закрытым членам внешнего класса.

public class Outer
{
    private int Value { get; set; }

    public class Inner
    {
        protected void ModifyOuterMember(Outer outer, int value)
        {
            outer.Value = value;
        }
    }
}

И теперь вместе с вышеуказанной функцией вы также можете наследовать от вложенных классов, как если бы они были классами верхнего уровня, как показано ниже.

public class Cheater : Outer.Inner
{
    protected void MakeValue5(Outer outer)
    {
        ModifyOuterMember(outer, 5);
    }
}

Эти функции предоставляют некоторые интересные возможности, в том числе предоставление доступа к определенным членам через несколько скрытые классы.

10
ответ дан 3 October 2019 в 21:34
поделиться

Вам нужно вызвать функцию AddAddress один раз для каждого адреса электронной почты, на который вы хотите отправить. У этой функции всего два аргумента: адрес_получателя_адрес и имя_получателя . Имя получателя не является обязательным и не будет использоваться, если оно не указано.

$mailer->AddAddress('recipient1@domain.com', 'First Name');
$mailer->AddAddress('recipient2@domain.com', 'Second Name');
$mailer->AddAddress('recipient3@domain.com', 'Third Name');

Вы можете использовать массив для хранения получателей, а затем использовать цикл для . Я надеюсь, что это помогает.

Я знаю, что если аргументы универсального метода содержат все требуемые типы, они могут быть выведены, например:

public static void Create<T1, T2>(T1 a, T2 b)
{
    // stuff
}

Эти два вызова идентичны:

Create<float, string>(1.0f, "test");
Create(1.0f, "test");

Поскольку T1 и T2 выводятся из переданных вами аргументов. Объединив эти знания с ключевым словом var, мы можем, добавив второй статический класс со статическим методом, например:

public abstract class Tuple
{
    public static Tuple<V1, V2> Create<V1, V2>(V1 v1, V2 v2)
    {
        return new Tuple<V1, V2>(v1, v2);
    }
}

Достичь этого эффекта:

var tup = Tuple.Create(1, "Hello, World!");

Это означает, что типы: variable "tup", type- параметры «Create» и возвращаемое значение «Create» выводятся из типов, которые вы передаете в качестве аргументов Create

. Полный код выглядит примерно так:

public abstract class Tuple
{
    public static Tuple<V1, V2> Create<V1, V2>(V1 v1, V2 v2)
    {
        return new Tuple<V1, V2>(v1, v2);
    }
}

public class Tuple<V1, V2> : Tuple
{
    public readonly V1 v1;
    public readonly V2 v2;

    public Tuple(V1 v1, V2 v2)
    {
        this.v1 = v1;
        this.v2 = v2;
    }
}

// Example usage:
var tup = Tuple.Create(1, "test");

Что дает вам полностью типизированные методы фабрики везде!

Create<float, string>(1.0f, "test");
Create(1.0f, "test");

Поскольку T1 и T2 выводятся из переданных вами аргументов. Объединив эти знания с ключевым словом var, мы можем, добавив второй статический класс с помощью статического метода, например:

public abstract class Tuple
{
    public static Tuple<V1, V2> Create<V1, V2>(V1 v1, V2 v2)
    {
        return new Tuple<V1, V2>(v1, v2);
    }
}

Достичь этого эффекта:

var tup = Tuple.Create(1, "Hello, World!");

Это означает, что типы: variable "tup", type- параметры «Create» и возвращаемое значение «Create» выводятся из типов, которые вы передаете в качестве аргументов Create

. Полный код выглядит примерно так:

public abstract class Tuple
{
    public static Tuple<V1, V2> Create<V1, V2>(V1 v1, V2 v2)
    {
        return new Tuple<V1, V2>(v1, v2);
    }
}

public class Tuple<V1, V2> : Tuple
{
    public readonly V1 v1;
    public readonly V2 v2;

    public Tuple(V1 v1, V2 v2)
    {
        this.v1 = v1;
        this.v2 = v2;
    }
}

// Example usage:
var tup = Tuple.Create(1, "test");

Что дает вам полностью типизированные методы фабрики везде!

Create<float, string>(1.0f, "test");
Create(1.0f, "test");

Поскольку T1 и T2 выводятся из переданных вами аргументов. Объединив эти знания с ключевым словом var, мы можем, добавив второй статический класс с помощью статического метода, например:

public abstract class Tuple
{
    public static Tuple<V1, V2> Create<V1, V2>(V1 v1, V2 v2)
    {
        return new Tuple<V1, V2>(v1, v2);
    }
}

Достичь этого эффекта:

var tup = Tuple.Create(1, "Hello, World!");

Это означает, что типы: variable "tup", type- параметры «Create» и возвращаемое значение «Create» выводятся из типов, которые вы передаете в качестве аргументов Create

. Полный код выглядит примерно так:

public abstract class Tuple
{
    public static Tuple<V1, V2> Create<V1, V2>(V1 v1, V2 v2)
    {
        return new Tuple<V1, V2>(v1, v2);
    }
}

public class Tuple<V1, V2> : Tuple
{
    public readonly V1 v1;
    public readonly V2 v2;

    public Tuple(V1 v1, V2 v2)
    {
        this.v1 = v1;
        this.v2 = v2;
    }
}

// Example usage:
var tup = Tuple.Create(1, "test");

Что дает вам полностью типизированные методы фабрики везде!

13
ответ дан 3 October 2019 в 21:34
поделиться

Пара, о которой я могу вспомнить:

[field: NonSerialized()]
public EventHandler event SomeEvent;

Это предотвращает сериализацию события. Поле 'field:' указывает, что атрибут должен быть применен к вспомогательному полю события.

Другая малоизвестная функция - переопределение обработчиков событий добавления / удаления:

public event EventHandler SomeEvent
{
    add
    {
        // ...
    }

    remove
    {
        // ...
    }
}
12
ответ дан 3 October 2019 в 21:34
поделиться

Простые намазание / конденсированное ORM-сопоставление Использование LINQ

Рассмотрим эту таблицу:

[MessageId] INT,
[MessageText] NVARCHAR(MAX)
[MessageDate] DATETIME

... и эта структура:

struct Message
{
    Int32 Id;
    String Text;
    DateTime Date;
}



вместо того, чтобы делать что-то вдоль Линии:

List<Message> messages = new List<Message>();

foreach (row in DataTable.Rows)
{
    var message = new Message
    {
        Id = Convert.ToInt32(row["MessageId"]),
        Text = Convert.ToString(row["MessageText"]),
        Date = Convert.ToDateTime(row["MessageDate"])
    };

    messages.Add(message);
}

Вы можете использовать LINQ и делать то же самое с меньшими строками кода, и на мой взгляд; Больше стиля. Вроде так:

var messages = DataTable.AsEnumerable().Select(r => new Message
{
    Id = Convert.ToInt32(r["MessageId"]),
    Text = Convert.ToString(r["MessageText"]),
    Date = Convert.ToDateTime(r["MessageDate"])
}).ToList();

Этот подход может быть вложенным, как и петли могут.

13
ответ дан 3 October 2019 в 21:34
поделиться

Вы можете поместить несколько атрибутов в одну пару квадратных скобок:

    [OperationContract, ServiceKnownType(typeof(Prism)), ServiceKnownType(typeof(Cuboid))]
    Shape GetShape();
14
ответ дан 3 October 2019 в 21:34
поделиться

Используйте «бросить»; вместо "бросить экс;" для сохранения трассировки стека

При повторной генерации исключения без добавления дополнительной информации используйте «throw» вместо «throw ex». Пустой оператор throw в блоке catch генерирует определенный IL, который повторно генерирует исключение, сохраняя исходную трассировку стека. "throw ex" теряет трассировку стека до исходного источника исключения.

55
ответ дан 22 November 2019 в 20:19
поделиться

Условная строка.Формат :

Применяет различное форматирование к числу в зависимости от того, является ли число положительным, отрицательным или нулем.

string s = string.Format("{0:positive;negative;zero}", i);

например

string format = "000;-#;(0)";

string pos = 1.ToString(format);     // 001
string neg = (-1).ToString(format);  // -1
string zer = 0.ToString(format);     // (0)
66
ответ дан 22 November 2019 в 20:19
поделиться