В чем разница между новым Object() и новым объектом {} в выражениях в С#
У меня есть следующий фрагмент кода:
Expression<Func<TSource, TDest>> expression = model => new TDest{};
// Result: {model => new TestModel(){}}
ReSharper реорганизует этот фрагмент с настройкой RedundantEmptyObjectOrCollectionInitializer
:
Expression<Func<TSource, TDest>> expression2 = model => new TDest();
// Result: {model => new TestModel()}
После этого мой код не работает. Какое влияние оказывают на инициализацию фигурных скобок?
Я нашел, что есть разница между new object()
и new {}
в С#? при переполнении стека, но оба экземпляра выглядят одинаково.
expression.GetType().ToString()
равен expression2.GetType().ToString()
В чем разница между этими инициализациями в деревьях выражений?:
var a = model => new TDest{};
var b = model => new TDest();
Ответы
Ответ 1
В обычном raw С# ответ будет "ничего". Однако, когда вы включаете деревья выражений, есть разница; как здесь видно
using System;
using System.Linq.Expressions;
public class C<TSource, TDest> where TDest : new() {
public Expression<Func<TSource, TDest>> Foo() => model => new TDest();
public Expression<Func<TSource, TDest>> Bar() => model => new TDest {};
}
компилируется как:
public Expression<Func<TSource, TDest>> Foo()
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(TSource), "model");
Expression arg_2E_0 = Expression.New(typeof(TDest));
ParameterExpression[] expr_2A = new ParameterExpression[1];
expr_2A[0] = parameterExpression;
return Expression.Lambda<Func<TSource, TDest>>(arg_2E_0, expr_2A);
}
public Expression<Func<TSource, TDest>> Bar()
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(TSource), "model");
Expression arg_38_0 = Expression.MemberInit(Expression.New(typeof(TDest)), Array.Empty<MemberBinding>());
ParameterExpression[] expr_34 = new ParameterExpression[1];
expr_34[0] = parameterExpression;
return Expression.Lambda<Func<TSource, TDest>>(arg_38_0, expr_34);
}
Таким образом, один из них включает Expression.MemberInit
(с пустым набором элементов MemberBinding
) в дополнение к Expression.New
. Это может привести к нарушению любого поставщика LINQ (или любого аналогичного анализа дерева выражений), который этого не ожидает.
Ответ 2
ReSharper дает вам лучшее предложение о том, как создать экземпляр класса TDest
.
Теоретически нет никакой разницы, поскольку и new TDest()
и new TDest {}
предоставят вам экземпляр TDest
.
Однако, когда вы используете выражение инициализации, это потому, что вы хотите установить значения общедоступных свойств или полей в TDest
.
class TDest
{
public string MyProperty { get; set; }
}
Таким образом, вы можете инициализировать класс TDest
задав значение MyProperty
. Например:
// Sample 1
new TDest { MyProperty = "This is the value of my property" };
// Sample 2
new TDest() { MyProperty = "This is the value of my property" };
В вашем случае ваш класс имеет конструктор без параметров, поэтому оба, пунктуаторы {, }
или operator ()
будут в порядке.
Для простых сценариев, где у вас есть конструктор без параметров, вы можете использовать только короткую форму TDest()
.
Но если бы у вас был, например, класс ниже.
class TDest
{
readonly ISomeInterface _someService;
public string MyProperty { get; set; }
public TDest(ISomeInterface someService)
{
_someService = someService;
}
}
И вы хотели инициализировать MyProperty
чем-то, а не значением инициализации по умолчанию (null, ссылочными типами), вы могли бы использовать полную инициализацию объекта. Например:
// Sample 3
new TDest(new MySomeServiceImplementation()) { MyProperty = "This is the value of my property" };
Надеюсь, это поможет!
Чтобы лучше понять, перейдите и посмотрите на Инициализаторы объектов С#.