Wie erstellen Sie einen Ausdruck.Lambda, wenn ein Typ erst zur Laufzeit bekannt ist?
Dies ist am besten zu erklären, mithilfe von code. Ich habe eine generische Klasse, die eine Methode hat, die eine Ganzzahl zurückgibt. Hier ist eine einfache version für die Zwecke zu erklären...
public class Gen<T>
{
public int DoSomething(T instance)
{
//Real code does something more interesting!
return 1;
}
}
Zur Laufzeit benutze ich die Reflexion zu entdecken, die Art von etwas, und dann wollen, erstellen Sie eine Instanz meiner Klasse Gen für diesen bestimmten Typ. Das ist einfach genug, und so geschehen...
Type fieldType = //This is the type I have discovered
Type genericType = typeof(Gen<>).MakeGenericType(fieldType);
object genericInstance = Activator.CreateInstance(genericType);
Möchte ich nun einen Ausdruck erstellen, der als parameter eine Instanz des generischen Typs und ruft dann die Methode DoSomething in der Art. So möchte ich den Ausdruck für die effektive Ausübung...
int answer = genericInstance.DoSomething(instance);
...außer, dass ich nicht die 'Instanz', bis irgendwann später in der Laufzeit und der genericInstance ist der generierte Typ wie oben zu sehen ist. Mein Versuch auf die Schaffung der Lambda-Ausdruck für dieses ist wie folgt...
MethodInfo mi = genericType.GetMethod("DoSomething",
BindingFlags.Instance | BindingFlags.Public);
var p1 = Expression.Parameter(genericType, "generic");
var p2 = Expression.Parameter(fieldType, "instance");
var x = Expression.Lambda<Func<genericType, fieldType, int>>
(Expression.Call(p1, mi, p2),
new[] { p1, p2 }).Compile();
...so dass später auf, die ich anrufen kann es mit etwas in dieser Art...
int answer = x(genericInstance, instance);
Natürlich, Sie nicht Func mit Instanz-Parameter, und so habe ich keine Ahnung wie ich das parametrisieren der Lambda-generation. Irgendwelche Ideen?
InformationsquelleAutor Phil Wright | 2011-10-18
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich denke Sie würden nur verwenden, die
Expression.Lambda
nimmt, dass die delegate-Typ als Typ dann eher als eine generische, und erstellen Sie Ihre Func-on-the-fly, wie Sie mitGen<>
:Diese zurück zu Delegieren, anstatt eine stark typisierte
Func
, man kann aber natürlich Stimmen Sie, wenn nötig (und scheinbar schwierig, wenn Sie nicht wissen, was Sie sind-casting), oder dynamisch aufrufen, mitDynamicInvoke
.BEARBEITEN:
Dieser scheint zu arbeiten, ohne die Notwendigkeit einer dynamischen aufrufen.
EDIT 2:
Eine stark vereinfachte version:
Ist es möglich zu erfassen Variablen in einem Ausdruck Baum? Ich würde helfen, zu erfassen, die genericInstance wie, dass wird sich nie ändern.
Hm, ich sehe. Lassen Sie mich sehen, was ich sonst noch mit oben kommen kann.
Bearbeitet. Geben, dass ein Schuss. Sie können in der Lage sein, um es zu vereinfachen ein wenig, aber ich denke das ist die richtige Spur.
Spot an, danke. Ich habe gerade versucht dies und es funktioniert großartig und ist schnell als gut.
InformationsquelleAutor vcsjones
Diese Antwort gilt nur, wenn Sie verwenden .NET 4.0.
Wenn Sie
genericInstance
dynamic
stattobject
Sie können dann aufrufen, dieDoSomething
- Methode auf, die direkt, und die dynamic language runtime kümmert sich um alles für Sie.Wenn Sie brauchen, um diese Klasse Struktur (
Gen<T>
), dann ich sehe nicht einen einfachen Weg, um die Tatsache, dass Sie nicht wissen, die ArtT
zur compile-Zeit. Wenn Sie möchten, rufen Sie die delegieren, müssen Sie entweder wissen, seine volle Typ zur compile-Zeit, oder du musst die Parameter als Objekte.Mit
dynamic
bekommt Sie zu verstecken die Komplexität des Erhaltens derMethodInfo
usw., und gibt Ihnen exzellente performance. Der einzige Nachteil gegenüberDynamicInvoke
dass ich sehe ist, dass ich glaube, Sie bekommen der anfängliche Aufwand zur Lösung des dynamischen Aufruf einmal pro call site. Die Bindungen werden zwischengespeichert, so dass Sie sehr schnell laufen ab dem zweiten mal ab, wenn Sie es rufen auf Objekte mit dem gleichen Typ.InformationsquelleAutor Jeffrey Sax
Ist es besser, zu akzeptieren, eine
object
und verwendenconvert
zu einer bekannten geben.Hier ist ein Beispiel, wie zu bauen, der Zugriff auf eine Eigenschaft von Namen, die auf unbekannte Tiefe:
Vermeidet zusätzliche Kosten von DynamicInvoke, wenn die Art der Stellvertretung unbekannt ist zur compile-Zeit.
InformationsquelleAutor Alex Zhukovskiy