4

ここに挑戦的なものがあります。メソッドにパラメーターとして渡されるプロパティの名前を暗黙的に決定するために、任意のメソッドを使用することは可能ですか?

(これは一見、別の質問の重複のように見えるかもしれませんが、キーとなるプロパティを常に操作している限り、微妙ではあるが重要な違いがあります)。

シナリオの例を次に示します。

    public class Foo
    {
        public string Bar { get; set; }
    }

    public void SomeStrangeMethod()
    {
        Foo foo = new Foo() { Bar = "Hello" };
        string result = FindContext(foo.Bar);  // should return "Bar"
    }

    public string FindContext(object obj)
    {
        // TODO? - figure out the property name corresponding to the passed parameter.  
        // In this example, we need to somehow figure out that the value of "obj"
        // is the value of the property foo.Bar, and return "Bar"            
    }

FindContext 内から、渡されたパラメーターは常にオブジェクトのプロパティであると想定します。問題は、どのオブジェクトかがわからないことです。

明らかに、不足しているコンテキストを提供する 2 番目のパラメーターを渡すことで、問題を簡単に解決できます。

FindContext(foo, foo.Bar);    
FindContext("Bar", foo.Bar);  

....しかし、それは私が望むものではありません。単一のパラメーターを渡して、値によって表されるプロパティ名を決定できるようにしたいと考えています。

パラメータが渡されたとき、FindContext のメソッド コンテキストには、これを判断するのに十分な情報が含まれていないことを理解しています。ただし、スタック トレースと IL を少し巧みに操作すれば、おそらくまだ可能です。これが可能でなければならないと私が考える理由は次のとおりです。

  1. FindContext に渡されるパラメーターは常に別のオブジェクトのプロパティでなければならないという要件があり、リフレクションを使用してそのプロパティ名を取得できることがわかっています。

  2. StackTrace を使用して、呼び出しコンテキストを取得できます。

  3. 呼び出しコンテキストから、使用されているシンボルを何らかの方法で見つけることができるはずです。

  4. そのシンボルから、プロパティ名および/または呼び出し元オブジェクトのタイプを取得できる必要があります。これは、(1) を介して呼び出し元オブジェクトのプロパティに変換できるはずです。

誰もこれを行う方法を知っていますか? 注: この質問は難しいですが、不可能ではないと思います。誰かが不可能な理由を証明できない限り、「不可能」という回答は受け付けません。

4

4 に答える 4

3

The MVVM Light Toolkit uses C#'s expression trees sugar support passing "properties" for the purpose of implementing INotifyPropertyChanging and INotifyPropertyChanged. For details, see ObservableObject.cs

void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
    var handler = PropertyChanged;
    if (handler != null)
    {
        var propertyName = GetPropertyName(propertyExpression);
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

The calling code can then use this:

RaisePropertyChanged(() => this.Property);

Instead of relying on hard-coded strings like this:

RaisePropertyChanged("Property");
于 2013-03-20T15:46:28.820 に答える
3

ラムダ式を渡すと、次のことができます

public class Foo
{
    public string Bar { get; set; }
}

public void SomeStrangeMethod()
{
    Foo foo = new Foo() { Bar = "Hello" };
    string result = GetName(()=>foo.Bar);  // should return "Bar"
    Debug.WriteLine(result); // "Bar"
}


public static string GetName<T>(Expression<Func<T>> expression)
{
    return ExtractPropertyName(expression);
}

/// <summary>
/// Extracts the name of a property from a suitable LambdaExpression.
/// </summary>
/// <param name="propertyExpression">The property expression.</param>
/// <returns></returns>
public static string ExtractPropertyName(LambdaExpression propertyExpression)
{
    if (propertyExpression == null)
    {
        throw new ArgumentNullException("propertyExpression");
    }

    var memberExpression = propertyExpression.Body as MemberExpression;
    if (memberExpression == null)
    {
        throw new ArgumentException(@"Not a member expression", "propertyExpression");
    }

    var property = memberExpression.Member as PropertyInfo;
    if (property == null)
    {
        throw new ArgumentException(@"Not a property", "propertyExpression");
    }

    var getMethod = property.GetGetMethod(true);
    if (getMethod.IsStatic)
    {
        throw new ArgumentException(@"Can't be static", "propertyExpression");
    }

    return memberExpression.Member.Name;
}
于 2013-03-20T15:46:33.830 に答える
1

Expressionでオブジェクトタイプを明示的に指定せずにからプロパティ名を見つけることができるようにするにExpressionは、拡張メソッドが必要です。

public static class ObjectExt
{
    public static string FindContext<T,TProp>(this T obj, Expression<Func<T,TProp>> expression) {
        return ( expression.Body as MemberExpression ).Member.Name;
    }
}

次に、それをコードサンプルに配置すると

public class Foo
{
    public string Bar { get; set; }
}

public void SomeStrangeMethod()
{
    Foo foo = new Foo() { Bar = "Hello" };
    string result = foo.FindContext(s => s.Bar);  // should return "Bar"
}
于 2013-03-20T16:17:29.157 に答える
1

いいえ - これは常に可能であるとは限りません。

3. Out of the calling context, we should be able to somehow locate the symbol being used.

これは失敗する部分です。実行時に、メソッド パラメーターに使用されているシンボルを取得することはできません (少なくとも直接ではありません)。Reflection ライブラリには、この種の分析またはメタデータを提供するツールはありません。

そうは言っても、これは多くのIL分析で可能になる可能性があります。Mono.Cecilなどのツールを使用してアセンブリを逆コンパイルした場合は、「呼び出しコンテキスト」を見つけてから、問題のメソッドへの呼び出しについて IL を調べます。

于 2013-03-20T15:38:12.970 に答える