6

更新: これは、C# 6 からの問題ではなくなりました。C# 6 では、このnameofようなシナリオに対処するためにオペレーターが導入されました ( MSDNを参照)。

:「<a href="https://stackoverflow.com/questions/11063502/getting-names-of-local-variables-and-parameters-at-run-time-through-lambda-exp">取得」を参照してくださいこの質問の一般化といくつかの回答については、実行時のラムダ式によるローカル変数 (およびパラメーター) の名前を参照してください。

Eric De Carufelによって提供されたものと同様のコードを使用して、ラムダ式を使用してINotifyPropertyChangedインターフェイスのリファクタリング セーフな実装を作成するというアイデアが気に入っています。

ArgumentExceptionリファクタリング セーフな方法で (またはその派生クラス) にパラメーター名を提供するために、同様の実装を試しています。

nullチェックを実行するための次のユーティリティ メソッドを定義しました。

public static void CheckNotNull<T>(Expression<Func<T>> parameterAccessExpression)
{
    Func<T> parameterAccess = parameterAccessExpression.Compile();
    T parameterValue = parameterAccess();
    CheckNotNull(parameterValue, parameterAccessExpression);
}

public static void CheckNotNull<T>(T parameterValue, 
    Expression<Func<T>> parameterAccessExpression)
{
    if (parameterValue == null)
    {
        Expression bodyExpression = parameterAccessExpression.Body;
        MemberExpression memberExpression = bodyExpression as MemberExpression;
        string parameterName = memberExpression.Member.Name;
        throw new ArgumentNullException(parameterName);
    }
}

引数の検証は、次の構文を使用してリファクタリング セーフな方法で実行できます。

CheckNotNull(() => arg);           // most concise
CheckNotNull(arg, () => args);     // equivalent, but more efficient

私の懸念は次の行にあります。

Expression bodyExpression = parameterAccessExpression.Body;
MemberExpression memberExpression = bodyExpression as MemberExpression;

AMemberExpressionは「フィールドまたはプロパティへのアクセス」を表します。INotifyPropertyChangedこの場合、ラムダ式はプロパティ アクセスになるため、正しく動作することが保証されています。

ただし、上記のコードでは、ラムダ式は意味的にはパラメーターアクセスであり、フィールドまたはプロパティ アクセスではありません。コードが機能する唯一の理由は、C# コンパイラが匿名関数でキャプチャされたローカル変数 (およびパラメーター) を、舞台裏でコンパイラによって生成されたクラス内のインスタンス変数に昇格させるためです。これは、 Jon Skeetによって裏付けられています。

私の質問は次のとおりです。この動作 (キャプチャされたパラメーターをインスタンス変数に昇格させる) は .NET 仕様内で文書化されていますか、それとも代替実装またはフレームワークの将来のリリースで変更される可能性のある単なる実装の詳細ですか? 具体的には、parameterAccessExpression.Body is MemberExpression返品する環境はありますfalseか?

4

1 に答える 1

0

クロージャ: おっしゃったように、パラメータ アクセスのために、C# コンパイラ (はい、具体的にはコンパイラ) は、キャプチャされたパラメータ変数の値を格納するためのインスタンス フィールドを含むクロージャ クラスを作成します。これは、C# コンパイラの将来のバージョンで変更される可能性がありますか? もちろん。おそらく、C# の将来のバージョンでは、生成されたクロージャ クラスにはランダムな名前の変数が含まれるでしょう。さらに、あなたが持っているコードは、他の .NET 言語では機能しない可能性があります。VB .NET は、C# とは少し異なる式ツリーとクロージャ クラスを生成することがあります...

あなたの現在の実装が構造体でも機能するかどうかはわかりません(記憶違いかもしれませんが...ボクシングに対処しようと考えている状況は、適用されるだけかもしれませんExpression<Func<T, object>>(読んで、自分で試してください)。

とにかく...これはすべて言った...C#の将来のバージョンで変更されますか?おそらくそうではありません。もしそうなら、おそらくそれを処理するために内部実装を変更できます...

パフォーマンスに関しては、ここで本当に注意してください。ラムダをコンパイルして評価する必要がないので、2つの引数を渡す方が効率的であるとすでに述べました....しかし、明確にするために、コンパイルして実行するたびにここで15〜30ミリ秒のヒットについて話している.評価。

于 2012-06-17T19:12:57.697 に答える