Possiedo un'applicazione di origine chiusa di terze parti che esporta un'interfaccia COM, che sto utilizzando nell'applicazione C# .NET tramite Interop. Questa interfaccia COM esporta molti oggetti che vengono visualizzati come System.Object fino a quando non li lancio nel tipo di interfaccia appropriato. Voglio assegnare una proprietà di tutti questi oggetti. Così:funzione generica con un vincolo "ha proprietà X"?
foreach (object x in BigComInterface.Chickens)
{
(x as Chicken).attribute = value;
}
foreach (object x in BigComInterface.Ducks)
{
(x as Duck).attribute = value;
}
Ma assegnando la proprietà è probabile (per ragioni specifiche per l'applicazione che sono inevitabili) per lanciare eccezioni da cui voglio recuperare, quindi voglio davvero un try/catch intorno ad ogni uno. Così:
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...
}
}
Ovviamente, sarebbe molto più pulito di fare questo:
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...
}
}
vedere il problema? Il mio valore x può essere di qualsiasi tipo, pertanto il compilatore non può risolvere .attribute. Chicken and Duck non sono in alcun tipo di albero ereditario e non condividono un'interfaccia che ha .attribute. Se lo facessero, potrei mettere un vincolo per quell'interfaccia su T. Ma dal momento che la classe è closed-source, non è possibile per me.
Quello che voglio, nella mia fantasia, è qualcosa di simile a un vincolo che richiede l'argomento di avere la proprietà .attribute indipendentemente dal fatto che implementa una determinata interfaccia. Vale a dire,
void SetAttribute<T>(T x, System.Object value) where T:hasproperty(attribute)
io non sono sicuro di cosa fare da qui se non per tagliare/incollare questo piccolo blocco try/catch per ciascuno di pollo, anatra, Vacca, Ovino, e così via.
La mia domanda è: che cosa è una buona soluzione per questo problema di voler richiamare una proprietà specifica su un oggetto quando l'interfaccia che implementa quella proprietà non può essere conosciuta in fase di compilazione?
Grazie, Reed. Ho provato la tecnica di Reflection - fa ciò di cui ho bisogno ma è un po 'lento. – catfood
Dato che non esiste un'interfaccia comune, non c'è modo di fare il richiamo generico veloce basato su vtable - devi fare una ricerca dinamica sul nome, e questo è sempre lento, Riflessione o no. –
@Pavel: Sì, è sempre lento, ma tecnicamente, è l'unico modo che funziona senza modificare le classi esistenti, fino a quando C# 4 non è disponibile. Non sto dicendo che è buono, ma piuttosto che funzionerebbe. –