Risposta lunga fino a venire. La riflessione è ottima in molte situazioni, orribile in alcuni, ma in quasi tutti i casi è lenta.
Esistono almeno 4 modi diversi per impostare una proprietà in .NET senza dover utilizzare la riflessione.
Ho pensato di dimostrarne uno: utilizzare alberi di espressione compilati. Si noti che la creazione di espressioni è piuttosto costosa, quindi è molto importante memorizzare nella cache il delegato con un build in un dizionario (ad esempio):
Expression Trees è stato introdotto in .NET35 ed è utilizzato per molte cose. Qui li uso per costruire un'espressione setter di proprietà e quindi compilarlo in un delegato.
L'esempio dimostra tempistica diversa per i diversi casi, ma qui sono i miei numeri: caso di controllo (hard coded): 0.02s Riflessione: 1.78s Espressione Albero: 0.06s
using System;
using System.Linq.Expressions;
namespace DifferentPropertSetterStrategies
{
class TestClass
{
public string XY
{
get;
set;
}
}
class DelegateFactory
{
public static Action<object, object> GenerateSetPropertyActionForControl(
)
{
return (inst, val) => ((TestClass) inst).XY = (string) val;
}
public static Action<object, object> GenerateSetPropertyActionWithReflection(
Type type,
string property
)
{
var propertyInfo = type.GetProperty(property);
return (inst, val) => propertyInfo.SetValue (inst, val, null);
}
public static Action<object,object> GenerateSetPropertyActionWithLinqExpression (
Type type,
string property
)
{
var propertyInfo = type.GetProperty(property);
var propertyType = propertyInfo.PropertyType;
var instanceParameter = Expression.Parameter(typeof(object), "instance");
var valueParameter = Expression.Parameter(typeof(object), "value");
var lambda = Expression.Lambda<Action<object, object>> (
Expression.Assign (
Expression.Property (Expression.Convert (instanceParameter, type), propertyInfo),
Expression.Convert(valueParameter, propertyType)),
instanceParameter,
valueParameter
);
return lambda.Compile();
}
}
static class Program
{
static void Time (
string tag,
object instance,
object value,
Action<object, object > action
)
{
// Cold run
action(instance, value);
var then = DateTime.Now;
const int Count = 2000000;
for (var iter = 0; iter < Count; ++iter)
{
action (instance, value);
}
var diff = DateTime.Now - then;
Console.WriteLine ("{0} {1} times - {2:0.00}s", tag, Count, diff.TotalSeconds);
}
static void Main(string[] args)
{
var instance = new TestClass();
var instanceType = instance.GetType();
const string TestProperty = "XY";
const string TestValue = "Test";
// Control case which just uses a hard coded delegate
Time(
"Control",
instance,
TestValue,
DelegateFactory.GenerateSetPropertyActionForControl()
);
Time(
"Reflection",
instance,
TestValue,
DelegateFactory.GenerateSetPropertyActionWithReflection (instanceType, TestProperty)
);
Time(
"Expression Trees",
instance,
TestValue,
DelegateFactory.GenerateSetPropertyActionWithLinqExpression(instanceType, TestProperty)
);
Console.ReadKey();
}
}
}
se c'è davvero una tale espressione 'dynamicCastedLocaleEntity.GetProperty (valori [j] .EntityPropertyName) = valore;', come fa il runtime sapere quali istanza vuoi dare il valore? –