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);
Для получения дополнительной информации см. здесь
" урожай " поступил бы по моему мнению. Некоторые атрибуты как [DefaultValue ()] также среди моего избранного.
" var" ключевое слово немного более известен, но что можно использовать его в.NET 2,0 приложения также (как долго, поскольку Вы используете.NET 3,5 компилятора и устанавливаете его для вывода 2,0 кодов), кажется, не известен очень хорошо.
Редактирование: kokos, благодарит указать?? оператор, это действительно действительно полезно. Так как это немного трудно к Google для него (как?? просто проигнорирован), вот страница документации MSDN для того оператора: ?? Оператор (Ссылка C#)
Не уверен, упоминался ли этот вопрос, но атрибут ThreadStatic действительно полезен. Это делает статическое поле статическим только для текущего потока.
[ThreadStatic]
private static int _ThreadStaticInteger;
Вы не должны включать инициализатор, потому что он выполняется только один раз для всего приложения, лучше сделать поле обнуляемым и проверить, является ли значение нулевым, прежде чем использовать его.
И еще одна вещь для потоков приложений ASP.NET используется повторно, так что если вы измените значение, оно может в конечном итоге использоваться для другого запроса страницы.
Тем не менее я нашел это полезным в нескольких случаях. Например, при создании пользовательского класса транзакции, который:
using (DbTransaction tran = new DbTransaction())
{
DoQuery("...");
DoQuery("...");
}
Конструктор DbTransaction устанавливает поле ThreadStatic на свое собственное значение и сбрасывает его на ноль в методе dispose. DoQuery проверяет статическое поле и, если! = Null, использует текущую транзакцию, если нет, то по умолчанию используется что-то другое. Мы избегаем необходимости передавать транзакцию каждому методу, и это облегчает перенос других методов, которые изначально не предназначались для использования с транзакцией внутри транзакции ...
Только одно использование:)
Я думаю, что одна из большинства недооцениваемых и менее известных функций 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);
}
}
Это - одна большая причина, что я люблю Лямбды и Деревья выражений прямо сейчас.
ОТЛАДКА #if директива препроцессору. Это Полезно для тестирования и отладки (хотя я обычно предпочитаю идти путем поблочного тестирования).
string customerName = null;
#if DEBUG
customerName = "Bob"
#endif
Это только выполнит блок кода, если Visual Studio будет установлена скомпилировать в режиме 'Debug'. Иначе блок кода будет проигнорирован компилятором (и grayed в Visual Studio).
Мой любимый прием использует , пустой указатель объединяет оператор и круглые скобки, чтобы автоволшебно инстанцировать наборов для меня.
private IList<Foo> _foo;
public IList<Foo> ListOfFoo
{ get { return _foo ?? (_foo = new List<Foo>()); } }
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# здесь, где это используется в большой степени:
Система. Время выполнения. Дистанционная работа. Прокси. RealProxy
, который Это включает Аспектно-ориентированному программированию в C#, и можно также сделать много другого необычного материала с ним.
Я сказал бы, что использование определенных системных классов для дополнительных методов очень удобно, например, Система. Перечисление, можно сделать что-то как ниже...
[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)) {
...
}
Это - просто пример, конечно - методы могли использовать немного больше работы...
Этот не "скрыт" так, поскольку это неверно называется.
Большое внимание обращено на алгоритмы "карта", "уменьшите", и "фильтр". То, что не понимает большинство людей, - то, что.NET 3.5 добавила все три из этих алгоритмов, но она дала им очень имена выхода SQL, на основе того, что они - часть LINQ.
"карта" => Выбор
Преобразовывает данные из одной формы в другой, "уменьшают" =>, Агрегат
Агрегировал значения в единственный результат"фильтр" =>, Где
данные Фильтров на основе критерии
способность использовать LINQ, чтобы сделать встроенная работа над наборами, которые раньше брали повторение и условные выражения, может быть невероятно ценной. Стоит изучить, как все дополнительные методы LINQ могут помочь сделать Ваш код намного более компактным и удобным в сопровождении.
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 */
});
}
, Так как анонимные делегаты были добавлены к 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);
Другие недогруженные операторы 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
Метод TrueForAll List<T>
:
List<int> s = new List<int> { 6, 1, 2 };
bool a = s.TrueForAll(p => p > 0);
Существуют операторы для выполнения implicit
и explicit
пользовательское преобразование типов между заявленным классом и одним или несколькими произвольными классами. implicit
оператор эффективно позволяет моделирование перегрузки assignement оператора, который возможен на языках, таких как C++, но не C#.
Это, кажется, не функция, через которую каждый приезжает очень часто, но это на самом деле используется в LINQ к библиотеке XML (System.Xml.Linq
), где можно неявно преобразовать строки в XName
объекты. Пример:
XName tagName = "x:Name";
я обнаружил эту функцию в этом статья о том, как моделировать множественное наследование в C#.
У Вас могут быть общие методы в неуниверсальном классе.
Прохладный прием для эмуляции функциональных "подстановочных" аргументов (как '_' в Haskell) при использовании лямбд:
(_, b, __) => b.DoStuff(); // only interested in b here
Только для ссылки - перечислимые бинарные операции с помощью дополнительного метода.
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();
}
}
}
Группы метода не известны.
Данный:
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);
Цепочка конструктора уже цитируется?
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();
Можно использовать дженерики для проверки (время компиляции), если аргумент метода реализует два интерфейса:
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);
}
}
То же с аргументом, который наследован от базового класса и интерфейса.
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.
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
Методы расширения могут быть вызваны на null
; это не вызовет выброса NullReferenceException
.
Пример приложения: вы можете определить альтернативу для ToString ()
под названием ToStringOrEmpty ()
, которая вернет пустая строка при вызове null
.
Вложенные классы могут получить доступ к закрытым членам внешнего класса.
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);
}
}
Эти функции предоставляют некоторые интересные возможности, в том числе предоставление доступа к определенным членам через несколько скрытые классы.
Вам нужно вызвать функцию 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");
Что дает вам полностью типизированные методы фабрики везде!
Пара, о которой я могу вспомнить:
[field: NonSerialized()]
public EventHandler event SomeEvent;
Это предотвращает сериализацию события. Поле 'field:' указывает, что атрибут должен быть применен к вспомогательному полю события.
Другая малоизвестная функция - переопределение обработчиков событий добавления / удаления:
public event EventHandler SomeEvent
{
add
{
// ...
}
remove
{
// ...
}
}
Простые намазание / конденсированное 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();
Этот подход может быть вложенным, как и петли могут.
Вы можете поместить несколько атрибутов в одну пару квадратных скобок:
[OperationContract, ServiceKnownType(typeof(Prism)), ServiceKnownType(typeof(Cuboid))]
Shape GetShape();
Используйте «бросить»; вместо "бросить экс;" для сохранения трассировки стека
При повторной генерации исключения без добавления дополнительной информации используйте «throw» вместо «throw ex». Пустой оператор throw в блоке catch генерирует определенный IL, который повторно генерирует исключение, сохраняя исходную трассировку стека. "throw ex" теряет трассировку стека до исходного источника исключения.
Применяет различное форматирование к числу в зависимости от того, является ли число положительным, отрицательным или нулем.
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)