generische Funktion mit einem "hat die Eigenschaft X" - Einschränkung?
Habe ich eine third-party-closed-source-Anwendung, die Exporte eine COM-Schnittstelle, die ich verwende in meinem C#.NET Anwendung über Interop. Diese COM-Schnittstelle exportiert viele Objekte, die alle zeigen, wie System.Objekt, bis ich warf Sie auf den entsprechenden interface-Typ. Ich möchte das zuweisen einer Eigenschaft aller dieser Objekte. Also:
foreach (object x in BigComInterface.Chickens)
{
(x as Chicken).attribute = value;
}
foreach (object x in BigComInterface.Ducks)
{
(x as Duck).attribute = value;
}
Aber die Zuordnung der Eigenschaft ist wahrscheinlich (für Anwendungs-spezifische Gründe, die unvermeidlich sind) zu werfen Ausnahmen, von denen ich möchte, sich zu erholen, so dass ich wirklich wollen eine try/catch um jeden. Also:
foreach (object x in BigComInterface.Chickens)
{
try
{
(x as Chicken).attribute = value;
}
catch (Exception ex)
{
//handle...
}
}
foreach (object x in BigComInterface.Ducks)
{
try
{
(x as Duck).attribute = value;
}
catch (Exception ex)
{
//handle...
}
}
Natürlich wäre es so viel sauberer, dies zu tun:
foreach (object x in BigComInterface.Chickens)
{
SetAttribute<Chicken>(x as Chicken, value);
}
foreach (object x in BigComInterface.Ducks)
{
SetAttribute<Duck>(x as Duck, value);
}
void SetAttribute<T>(T x, System.Object value)
{
try
{
x.attribute = value;
}
catch
{
//handle...
}
}
Sehen Sie das problem? Meine x Wert kann einen beliebigen Typ haben, damit der compiler nicht auflösen kann .Attribut. Huhn und Ente sind nicht in jeder Art von Vererbung Baum und Sie nicht teilen eine Schnittstelle, die hat .Attribut. Wenn Sie es Taten, ich könnte eine Einschränkung für die Schnittstelle auf T. Aber da die Klasse "closed-source", das ist für mich nicht möglich.
Was ich will, in meiner Phantasie, ist so etwas wie eine Einschränkung erfordern das argument haben .Attribut-Eigenschaft unabhängig davon, ob es eine bestimmte Schnittstelle implementiert. Zu Witz,
void SetAttribute<T>(T x, System.Object value) where T:hasproperty(attribute)
Ich bin nicht sicher was zu tun hier andere als Ausschneiden/einfügen dieses kleine try/catch-block für jedes Huhn, Ente, Kuh, Schaf, und so weiter.
Meine Frage ist: Was ist eine gute Abhilfe für dieses problem wollen, rufen Sie eine bestimmte Eigenschaft auf ein Objekt, wenn die Schnittstelle, die implementiert, dass die Eigenschaft nicht zum Zeitpunkt der Kompilierung bekannt?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Leider, dies ist schwierig derzeit. In C# 4, der dynamische Typ kann helfen, ganz ein bisschen mit diesem. COM-interop ist einer der Orte, die Dynamik wirklich glänzt.
Jedoch in der Zwischenzeit, ist die einzige option, die Ihnen erlaubt, jegliche Art von Objekt, ohne Beschränkungen in Bezug auf Schnittstellen, wäre, wieder mit der spiegelung.
Können Sie mithilfe von reflektion zu finden, das "Attribut" - Eigenschaft, und legen Sie dessen Wert zur Laufzeit.
Gut, je nachdem, wie gut dein exception-handling-code ist (und wenn ich mich nicht Irre, könnte es durchaus so) mit folgender trick könnte helfen:
Nicht zu verletzen und die CHEMISCHE Prinzip, die Sie verwenden können, Reflexion. Wenn Sie wirklich wollen, dass Generika verwendet werden, könnte man eine wrapper-Klasse für jede Art von 3rd-party-Objekts und haben den wrapper implementieren eine Schnittstelle, die Sie verwenden können, zu beschränken generic type Arguments.
Ein Beispiel, wie es getan werden könnte mit der Reflexion. Code ist nicht getestet, aber.
Wenn Sie zu beschleunigen, den code für die Leistung, die Sie konnte, cache FieldInfo-und PropertyInfo pro Art der
chickenDuckOrWhatever
und konsultieren Sie das Wörterbuch ersten, bevor überlegungen.TIPP: nicht zu fest die
attributeName
als Zeichenfolge, die Sie konnte Verwendung von C# 6-Funktion nameof. Wie nameof(Hähnchen.AttributeName) zum Beispiel.Leider der einzige Weg, dies zu tun ist, erhält der parameter Typ mit einer Schnittstelle, die festlegt, dass Eigentum und ist auf allen Arten.
Da Sie nicht die Quelle dieser unmöglich sein wird, zu implementieren und als solche müssen Sie irgendeine Art von Abhilfe. C# ist statisch typisiert und als solche bietet keine Unterstützung für die Art von duck-typing, die Sie verwenden möchten, hier. Das beste, was demnächst (in C# 4) wäre die Art des Objekts als
dynamic
und lösen Sie die Eigenschaft Anrufe bei der Ausführung (beachten Sie, dass dieser Ansatz wäre auch nicht generisch sein, wie Sie nicht erzwingen kann einen generischen Typ-parameter alsdynamic
).