Kiuhnm
2009-07-21 21:51:57 UTC
Sia IA un'interfaccia:
interface IA
{
int f1();
int f2();
}
Sia B una seconda "versione" dell'interfaccia IA:
abstract class B : IA
{
public abstract int f1();
int IA.f2() { return (int)f2(); }
public abstract char f2();
}
B espone IA.f1, ma ""nasconde"" IA.f2 presentando l'alternativa IB.f2.
L'"interfaccia" B è equivalente a IA a livello d'informazione, quindi
l'utente può limitarsi a implementare la sola B e quest'ultima
provvederà ad implementare IA.
B è, in una parola, retrocompatibile.
La classe User implementa l'"interfaccia" B in questo modo:
class User : B
{
public override int f1() { return 1; }
public override char f2() { return 'a'; }
}
Il risultato è quello che ci si aspetterebbe:
il codice
static void Main()
{
User user = new User();
IA userA = user;
B userB = user;
Console.WriteLine("userA.f1() = {0}", userA.f1());
Console.WriteLine("userA.f2() = {0}", userA.f2());
Console.WriteLine("userB.f2() = {0}", userB.f2());
}
stampa
userA.f1() = 1
userA.f2() = 97
userB.f2() = a
Il problema è che B non è un'interfaccia agli occhi del C# quindi va
implementata come classe. Dato che l'ereditarietà multipla non è
disponibile in C#, questo pattern risulta in pratica inutilizzabile.
Studiando i generics in C# ho notato che IEnumerable<T> deriva da
IEnumerable. Fin qui niente di strano.
La sorpresa è stata scoprire che per implementare IEnumerable<T> devo
fornire l'implementazione di ben due metodi praticamente identici!
Penso che nel 99.9% dei casi uno dei due metodi chiami quell'altro (o
entrambi un metodo d'appoggio). Tra l'altro occorre implementare almeno
uno dei due metodi in modo esplicito.
Non mi sembra una soluzione molto pulita.
La situazione con IEnumerator<T> è analoga.
Mi piacerebbe sapere cosa pensate di questa situazione. Vi è capitato in
ambito reale di sentire la mancanza dell'ereditarietà multipla o no?
Kiuhnm
interface IA
{
int f1();
int f2();
}
Sia B una seconda "versione" dell'interfaccia IA:
abstract class B : IA
{
public abstract int f1();
int IA.f2() { return (int)f2(); }
public abstract char f2();
}
B espone IA.f1, ma ""nasconde"" IA.f2 presentando l'alternativa IB.f2.
L'"interfaccia" B è equivalente a IA a livello d'informazione, quindi
l'utente può limitarsi a implementare la sola B e quest'ultima
provvederà ad implementare IA.
B è, in una parola, retrocompatibile.
La classe User implementa l'"interfaccia" B in questo modo:
class User : B
{
public override int f1() { return 1; }
public override char f2() { return 'a'; }
}
Il risultato è quello che ci si aspetterebbe:
il codice
static void Main()
{
User user = new User();
IA userA = user;
B userB = user;
Console.WriteLine("userA.f1() = {0}", userA.f1());
Console.WriteLine("userA.f2() = {0}", userA.f2());
Console.WriteLine("userB.f2() = {0}", userB.f2());
}
stampa
userA.f1() = 1
userA.f2() = 97
userB.f2() = a
Il problema è che B non è un'interfaccia agli occhi del C# quindi va
implementata come classe. Dato che l'ereditarietà multipla non è
disponibile in C#, questo pattern risulta in pratica inutilizzabile.
Studiando i generics in C# ho notato che IEnumerable<T> deriva da
IEnumerable. Fin qui niente di strano.
La sorpresa è stata scoprire che per implementare IEnumerable<T> devo
fornire l'implementazione di ben due metodi praticamente identici!
Penso che nel 99.9% dei casi uno dei due metodi chiami quell'altro (o
entrambi un metodo d'appoggio). Tra l'altro occorre implementare almeno
uno dei due metodi in modo esplicito.
Non mi sembra una soluzione molto pulita.
La situazione con IEnumerator<T> è analoga.
Mi piacerebbe sapere cosa pensate di questa situazione. Vi è capitato in
ambito reale di sentire la mancanza dell'ereditarietà multipla o no?
Kiuhnm