web-dev-qa-db-ja.com

C#の式でのnew Object()とnew 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()}

その後、私のコードは機能しません。中括弧は初期化にどのような影響を与えますか?
見つかったC#のnew object()new {}の違いは?スタックオーバーフローでは、両方のインスタンスが同じように見えます。

expression.GetType().ToString()expression2.GetType().ToString()と等しい

式ツリーのこれらの初期化の違いは何ですか?:

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

通常の生のC#では、答えは「なし」になります。ただし、式ツリーを使用する場合は違いがあります。ご覧のとおり こちら

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

そのため、それらの1つには、Expression.MemberInitに加えて、Expression.NewMemberBinding要素の空のセット)が含まれます。これは、LINQプロバイダー(または同様の式ツリー分析)を混乱させる可能性があります。

104
Marc Gravell

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" };

あなたの場合、あなたのクラスにはパラメータなしのコンストラクタがあるので、両方の句読点{, }または演算子()で十分です。

パラメーターなしのコンストラクターがある単純なシナリオでは、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" };

うまくいけばそれが役立つ!

より良いアイデアを得るには、C#Object Initializersをご覧ください。

5
Alex.H