Recentemente ho affrontato un problema simile. Ho una libreria di classi di terze parti contenente una gerarchia di classi (diciamo IBase, Base e Derived, dove IBase è in realtà un'interfaccia).
public interface IBase {...}
public class Base : IBase {...}
public class Derived : Base {...}
Quindi, ho una mia classe che contiene un riferimento ext a IBase. Il tipo concreto di ext può essere Base così come Derivato.
public class MyClass {
// other stuff
public IBase ext;
}
Quello che in realtà serviva era un metodo AddedMethod virtuale() definito all'interno IBase e sovrascritto in ogni classe discendente, ma che non era praticabile. Quindi, si potrebbe essere tentati di definire una classe che contiene un insieme di metodi di estensione di overload:
public static class MyExtensions
{
public static void AddedMethod(this IBase arg) {...}
public static void AddedMethod(this Base arg) {...}
public static void AddedMethod(this Derived arg) {...}
}
poi, chiamare ext.AddedMethod() su MyClass oggetti. Questo non funziona: poiché i metodi di estensione sono legati staticamente, il primo metodo (ad esempio AddedMethod (questo IBase arg)) viene sempre chiamato, indipendentemente dal tipo effettivo di ext. Il problema può essere aggirato attraverso la definizione di un unico metodo di estensione su IBase, quindi utilizzando riflessione per selezionare la corretta istanza di un metodo statico privato il cui tipo di argomento corrisponde al tipo effettivo passato al metodo di estensione:
public static class MyExtensions
{
// just one extension method
public static void AddedMethod(this IBase arg){
// get actual argument type
Type itsType = arg.GetType();
// select the proper inner method
MethodInfo mi = typeof(MyExtensions).GetMethod("innerAddedMethod",
BindingFlags.NonPublic | BindingFlags.Static,
null,
new Type[] { itsType },
null);
// invoke the selected method
if (mi != null) {
mi.Invoke(null, new object[] { arg });
}
}
private static void innerAddedMethod(Base arg) {
// code for Base type arg
}
private static void innerAddedMethod(Derived arg) {
// code for Derived type arg
}
Sia una nuova classe derivata Derived2 dovrebbe essere aggiunta alla gerarchia IBase, dovremo semplicemente aggiungere alla classe MyExtensions un innerAddedMethod() sovraccarico che accetta Derived2 come argomento.
L'estensione non deve essere statica? – Alex
Sì, mi mancava:/ – ozanbora
Hai * bisogno * di risolvere il secondo metodo di estensione se si tratta di un oggetto B ma hai un riferimento A ad esso? Dopotutto, chiamare i metodi virtuali sul riferimento A si risolverà comunque sull'oggetto B. Sei tu a controllare le classi A e B? In tal caso, non dovresti comunque utilizzare un metodo di estensione, ma modifica le classi con metodi normali. – nvoigt