C # Expression Tree zum Aufrufen der Basisklasseneigenschaft get-Methode

.net-4.5 c# expression-trees reflection

Frage

Ich habe eine Ausdrucksstruktur erstellt, die Parameter aus einer Klasse ableitet und sie aufruft, um Werte in einer anderen Klasse festzulegen. Es funktioniert sehr gut für die meisten Typen, aber es schlägt bei einem abgeleiteten Typ fehl. Wenn ich habe:

public class A
{
    public string MyString {get; set;}
}

und

public class B : A
{

}

Wenn ich diesen Ausdrucksbaumcode verwende (wobei value die abgeleitete Instanz ist):

// Get the type of the object for caching and ExpressionTree purposes
var objectType = value.GetType();
// Define input parameter
var inputObject = Expression.Parameter( typeof( object ), "value" );

var properties = objectType.GetProperties( BindingFlags.Instance | BindingFlags.Public );
foreach (var property in properties)
{
    Expression.Property( Expression.ConvertChecked( inputObject, property.DeclaringType ), property.GetGetMethod() )
}

Ich werde diese Ausnahme erhalten:

{System.ArgumentException: The method 'My.Namespace.A.get_MyString' is not a property accessor
at System.Linq.Expressions.Expression.GetProperty(MethodInfo mi)...

Was mache ich hier falsch?

Akzeptierte Antwort

Sie müssen die Eigenschaft selbst und nicht die Getter-Methode dafür verwenden:

foreach (var property in properties)
{
    Expression.Property( 
         Expression.ConvertChecked( inputObject, property.DeclaringType ),
         property);
}

Im Grunde müssen Sie diese Property-Methode anstelle dieser überladenen Property-Methode verwenden

AKTUALISIEREN

Für GetGetMethod Ansatz - Wenn var objectType gleich A Typ ist, dann funktioniert es. Wenn es gleich B , dann funktioniert es nicht.

Ich vermute, dass das Problem in property.DeclaringType . In beiden Fällen ist es A Typ, als Eigenschaft deklariert. Aber dieser Code wird verschiedene ReflectedType für dieselbe Eigenschaft zurückgeben:

var reflectingTypeForA = typeof(A).GetProperty("MyString").GetGetMethod().ReflectedType;
var reflectingTypeForB = typeof(B).GetProperty("MyString").GetGetMethod().ReflectedType;

Für A es A , und für B es B . Meine Vermutung ist, dass für B Fall Expression.Property Logik überprüft, dass property.DeclaringType ist A , aber GetGetMethod hat ReflectedType gleich B , so dass es denkt, dass es die Eigenschaft eines anderen Objekts ist. Ich habe keine Beweise dafür, aber nur diese Mitglieder unterscheiden sich zwischen zwei GetGetMethod-Aufrufe

UPDATE2

Hier ist ein Code, der von Expression.Property (MethodInfo-Methode) verwendet wird:

private static PropertyInfo GetProperty(MethodInfo mi)
{
    Type type = mi.DeclaringType;
    BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic;
    flags |= (mi.IsStatic) ? BindingFlags.Static : BindingFlags.Instance;
    PropertyInfo[] props = type.GetProperties(flags);
    foreach (PropertyInfo pi in props)
    {
        if (pi.CanRead && CheckMethod(mi, pi.GetGetMethod(true)))
        {
            return pi;
        }
        if (pi.CanWrite && CheckMethod(mi, pi.GetSetMethod(true)))
        {
            return pi;
        }
    }
    throw new SomeException();
}

private static bool CheckMethod(MethodInfo method, MethodInfo propertyMethod) { 
    if (method == propertyMethod) {
        return true; 
    } 
    // If the type is an interface then the handle for the method got by the compiler will not be the
    // same as that returned by reflection. 
    // Check for this condition and try and get the method from reflection.
    Type type = method.DeclaringType;
    if (type.IsInterface && method.Name == propertyMethod.Name && type.GetMethod(method.Name) == propertyMethod) {
        return true; 
    }
    return false; 
} 

Das Problem ist in dieser Zeile:

if (method == propertyMethod) {
    return true; 
} 

Wenn Sie MethodInfo von GetGetMethod von Typ A abrufen, unterscheidet es sich von MethodInfo von Typ B , und diese Prüfung gibt false zurück. Ein solches Beispiel gibt auch false zurück:

var propertyAGetter = typeof(A).GetProperty("MyString").GetGetMethod();
var propertyBGetter = typeof(B).GetProperty("MyString").GetGetMethod();
bool areTheSame = propertyAGetter == propertyBGetter; // it equals to false


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow