2016-06-30 9 views
1

私はテストAPIを設計しています。私のようなAPIを持つようにしたい:入力として動的パラメータを取るラムダからプロパティ名を取得

// There is a dynamic object which should be tested to have certain properties. 
dynamic result = SomeMethod(); 

AssertPropertyIsNotNull(resut, o => o.Title); 
AssertPropertyIsNotNull(resut, o => o.City.Name); 

私はそれはそれはのように失敗したプロパティを主張するTestProperty方法を書きたいと適切なメッセージを示しています。ここでは、この例では

private void AssertPropertyIsNotNull(dynamic result, Func<dynamic, object> propertySelector) 
{ 
    var propertyPath = GetPropertyPathFromFunc(propertySelector); 
    var errorMessage = $"{propertyPath} is not filled properly." 
    Assert.IsNotNull(propertySelector(result), errorMessage); 
} 

、私はGetPropertyPathFromFuncの体が必要です。

質問どのように私は、入力としてo => City.Nameのようなラムダを取得し、結果として"City.Name"のような文字列を返すメソッドを書くことができます。

+0

http://stackoverflow.com/questions/8215449/c-sharp-converting-lambda-expression-function-to-descriptive-string? – tire0011

答えて

2

dynamicを使用しているので、型の安全性とコンパイル時のメンバー名チェックのチェックが緩くなり、文字列をプロパティ名として使用することに違いはありません。

ここに解決策があります。広範なエラーチェックと例外処理が必要です。リフレッシュオーバーヘッドを減らすためにキャッシングメカニズムを追加することもできます。

public static bool IsPropertyNull(dynamic obj, string propertyName) 
{ 
    var path = propertyName.Split('.'); 
    object tempObject = obj; 
    for (int i = 0; i < path.Length; i++) 
    { 
     PropertyInfo[] dynamicProperties = tempObject.GetType().GetProperties(); 
     var property = dynamicProperties.Single(x => x.Name == path[i]); 
     tempObject = property.GetValue(tempObject); 
    } 
    return tempObject == null; 
} 

bool isTitleNull = IsPropertyNull(result, "Title"); 
bool isCityNameNull = IsPropertyNull(result, "City.Name"); 
1

述べたように、残念ながらdynamicは、現在C#コンパイラによって実装される式ツリーに使用することができません。代わりに、アクセスされたプロパティ名を収集するカスタム動的オブジェクトを使用してデリゲートを呼び出すこともできます。私はこれを以下に実証しました。これは、あなたが与えた制限された構文でしか機能しないことに注意してください。もっと複雑なものを処理するために多くの努力をしていません。

private static string GetPropertyPathFromFunc(Func<dynamic, object> propertySelector) 
{ 
    var collector = new PropertyNameCollector(); 
    propertySelector(collector); 
    return collector.Name; 
} 

private class PropertyNameCollector : DynamicObject 
{ 
    public string Name { get; private set; } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     if (!string.IsNullOrEmpty(Name)) 
      Name += "."; 
     Name += binder.Name; 
     result = this; 
     return true; 
    } 
} 
関連する問題