Ho modificato il post di cui sopra per gsharp realtà impostare direttamente il valore e renderlo un po 'più facile da usare. Non è l'ideale in quanto vi è l'introduzione della funzione DynamicCast che richiede di conoscere il tuo tipo in anticipo. Il mio obiettivo era quello di cercare di mantenerli fortemente digitati e non restituire oggetti ed evitare parole chiave dinamiche. Inoltre, mantieni la "magia" al minimo.
public static T DynamicCast<T>(this object value)
{
return (T) value;
}
public static object GetPropertyValue<T>(this PropertyInfo propertyInfo, T objectInstance)
{
if (typeof(T) != propertyInfo.DeclaringType)
{
throw new ArgumentException();
}
var instance = Expression.Parameter(propertyInfo.DeclaringType, "i");
var property = Expression.Property(instance, propertyInfo);
var convert = Expression.TypeAs(property, propertyInfo.PropertyType);
var lambda = Expression.Lambda(convert, instance).Compile();
var result = lambda.DynamicInvoke(objectInstance);
return result;
}
public static void SetPropertyValue<T, TP>(this PropertyInfo propertyInfo, T objectInstance, TP value)
where T : class
where TP : class
{
if (typeof(T) != propertyInfo.DeclaringType)
{
throw new ArgumentException();
}
var instance = Expression.Parameter(propertyInfo.DeclaringType, "i");
var argument = Expression.Parameter(propertyInfo.PropertyType, "a");
var setterCall = Expression.Call(
instance,
propertyInfo.GetSetMethod(),
Expression.Convert(argument, propertyInfo.PropertyType));
var lambda = Expression.Lambda(setterCall, instance, argument).Compile();
lambda.DynamicInvoke(objectInstance, value);
}
Esempi:
public void Get_Value_Of_Property()
{
var testObject = new ReflectedType
{
AReferenceType_No_Attributes = new object(),
Int32WithRange1_10 = 5,
String_Requires = "Test String"
};
var result = testObject.GetType().GetProperty("String_Requires").GetPropertyValue(testObject).DynamicCast<string>();
result.Should().Be(testObject.String_Requires);
}
public void Set_Value_Of_Property()
{
var testObject = new ReflectedType
{
AReferenceType_No_Attributes = new object(),
Int32WithRange1_10 = 5,
String_Requires = "Test String"
};
testObject.GetType().GetProperty("String_Requires").SetPropertyValue(testObject, "MAGIC");
testObject.String_Requires.Should().Be("MAGIC");
}
È potrebbe scrivere un metodo di supporto che utilizza MakeGenericMethod o un albero di espressione per fare un lambda fare la chiamata digitato per chiamare dynamic_cast in base all'oggetto PropertyInfo ed evitare di dover per conoscerlo in anticipo. Ma questo è meno elegante.
fonte
2017-06-23 06:08:44
Qual è il tuo obiettivo? Dici che vuoi creare un'espressione lambda; hai solo bisogno del delegato compilato ('functionThatGetsValue'), o ti serve anche l'albero delle espressioni intermedie (' expression')? – LukeH
@LukeH, solo il delegato compilato. Grazie. (Il mio obiettivo è quello di scorrere un elenco di oggetti e leggere tutti i valori delle proprietà. Per ottenere un po 'di prestazioni, voglio farlo in questo modo invece di usare il riflesso) – gsharp
Quando ho cercato di ottenere risultati simili, ho finito con restituendo Func e inoltrando il valore restituito a un tipo di proprietà specifico sul lato del chiamante. –