Tengo el siguiente fragmento de código:
Expression<Func<TSource, TDest>> expression = model => new TDest{}; // Result: {model => new TestModel(){}} ReSharper refactoriza este fragmento con la configuración RedundantEmptyObjectOrCollectionInitializer :
Expression<Func<TSource, TDest>> expression2 = model => new TDest(); // Result: {model => new TestModel()} Después de eso, mi código no funciona. ¿Qué influencia tienen las llaves en la inicialización?
Encontré ¿Cuál es la diferencia entre el new object() y el new {} en C#? en Stack Overflow, pero ambas instancias parecen iguales.
expression.GetType().ToString() es igual a expression2.GetType().ToString()
¿Cuál es la diferencia entre estas inicializaciones en los árboles de expresión?:
var a = model => new TDest{}; var b = model => new TDest();En C# sin formato normal, la respuesta sería "nada". Sin embargo, cuando involucra árboles de expresión, hay una diferencia; como se puede ver aquí
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 {}; }compila como:
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); } Entonces, uno de ellos involucra un Expression.MemberInit (con un conjunto vacío de elementos MemberBinding ) además de Expression.New . Esto puede molestar a cualquier proveedor de LINQ (o cualquier análisis de árbol de expresión similar) que no lo espere.
ReSharper le ofrece una mejor sugerencia sobre cómo instanciar la clase TDest .
En teoría, no hay ninguna diferencia ya que tanto el new TDest () como new TDest {} le proporcionarán una instancia de TDest .
Sin embargo, cuando usa la expresión de inicialización, es porque desea establecer valores de propiedades públicas o campos en TDest .
class TDest { public string MyProperty { get; set; } } Entonces podría inicializar la clase TDest estableciendo un valor en MyProperty . P.ej:
// Sample 1 new TDest { MyProperty = "This is the value of my property" }; // Sample 2 new TDest() { MyProperty = "This is the value of my property" }; En su caso, su clase tiene un constructor sin parámetros, por lo que tanto los signos de puntuación {, } como los operadores () estarían bien.
Para escenarios simples donde tiene un constructor sin parámetros, puede usar solo la forma TDest() .
Pero si tuviera, por ejemplo, la siguiente clase.
class TDest { readonly ISomeInterface _someService; public string MyProperty { get; set; } public TDest(ISomeInterface someService) { _someService = someService; } } Y quería inicializar MyProperty con algo en lugar de su valor de inicialización predeterminado (nulo, tipos de referencia), podría usar la inicialización completa del objeto. P.ej:
// Sample 3 new TDest(new MySomeServiceImplementation()) { MyProperty = "This is the value of my property" };¡Espero que ayude!
Para tener una mejor idea, vaya y eche un vistazo a C# Object Initializers .