C#中表达式中的新Object()和新Object {}之间有什么区别?

时间:2018-04-09 13:33:33

标签: c# .net resharper

我有以下代码段:

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()}

之后,我的代码不起作用。花括号对初始化有什么影响?我在Stack Overflow上找到 What is the Difference Between new object() and new {} in C#? ,但两个实例看起来都相同。

expression.GetType().ToString()等于 expression2.GetType().ToString()

表达式树中这些初始化之间有什么区别?:

var a = model => new TDest{};
var b = model => new TDest();

2 个答案:

答案 0 :(得分:104)

在常规的原始C#中,答案是&#34;没有&#34;。但是,当涉及表达式树时,存在差异;可以看出here

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提供程序(或任何类似的表达式树分析)。

答案 1 :(得分:5)

ReSharper正在为您提供有关如何实例化TDest类的更好建议。

理论上,由于new TDest ()new TDest {}都会为您提供TDest的实例,因此没有任何差异。

但是,当您使用初始化表达式时,它是因为您想在TDest中设置公共属性或字段的值。

class TDest
{
    public string MyProperty { get; set; }
}

因此,您可以初始化TDest类,将值设置为MyProperty。 E.g:

// Sample 1
new TDest { MyProperty = "This is the value of my property" };

// Sample 2
new TDest() { MyProperty = "This is the value of my property" };

在你的情况下,你的类有一个无参数的构造函数,所以标点符号{, }或运算符()都可以。

对于有无参数构造函数的简单场景,您只能使用TDest()缩写形式。

但是,如果您有以下类别。

class TDest
{
    readonly ISomeInterface _someService;

    public string MyProperty { get; set; }

    public TDest(ISomeInterface someService)
    {
        _someService = someService;
    }
}

并且您希望使用某些内容而不是其默认初始化值(null,引用类型)初始化MyProperty,您可以使用完整对象初始化。 E.g:

// Sample 3
new TDest(new MySomeServiceImplementation()) { MyProperty = "This is the value of my property" };

希望它有所帮助!

要想有更好的主意,请查看 C# Object Initializers