Ein offener Delegat ist ein Delegat für eine Instanzmethode ohne Ziel. Um ihn aufzurufen, müssen Sie das Ziel als erstes Argument angeben. Sie sind eine clevere Möglichkeit, Code zu optimieren, der sonst Reflexion verwenden würde und eine schlechte Leistung hätte. Für eine Einführung in offene Delegaten siehe dieses. In der Praxis würden Sie teuren Reflexionscode verwenden, um diese offenen Delegaten zu erstellen, aber dann könnten Sie sie sehr preiswert als einfachen Delegatenaufruf aufrufen.
Ich versuche, Code zu schreiben, der eine beliebige PropertyInfo in einen solchen Delegaten für dessen Setter umwandelt. Bisher bin ich auf dies gekommen:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace Test
{
class TestClass
{
static Action MakeSetterDelegate(PropertyInfo property)
{
MethodInfo setMethod = property.GetSetMethod();
if (setMethod != null && setMethod.GetParameters().Length == 1) //überspringt unangenehme Indexeigenschaften
{
//Um an den Delegaten binden zu können, müssen wir einen Delegaten
//Typ erstellen wie: Action anstatt Action.
//Wir verwenden Reflexion, um das zu tun
Type setterGenericType = typeof(Action<,>);
Type delegateType = setterGenericType.MakeGenericType(new Type[] { typeof(T), property.PropertyType });
var untypedDelegate = Delegate.CreateDelegate(delegateType, setMethod);
//Wir verpacken den Action Delegaten in einen Action
Action setter = (instance, value) =>
{
untypedDelegate.DynamicInvoke(new object[] { instance, value });
};
return setter;
}
else
{
return null;
}
}
int TestProp
{
set
{
System.Diagnostics.Debug.WriteLine("Set-Methode für TestProp aufgerufen");
}
}
static void Test()
{
PropertyInfo property = typeof(TestClass).GetProperty("TestProp");
Action setter = MakeSetterDelegate(property);
TestClass instance = new TestClass();
setter(instance, 5);
}
}
}
Ein ähnlicher Code würde für den Getter geschrieben werden. Es funktioniert, aber der Setter-Delegat verwendet ein DynamicInvoke, um von einem Action<derivedType> in ein Action<object> zu konvertieren, was meiner Vermutung nach einen guten Teil der Optimierung frisst, die ich erreichen möchte. Deshalb lauten die Fragen:
- Ist das DynamicInvoke ein echtes Problem?
- Gibt es einen Weg daran vorbei?