Perché C# non supporta i tipi generici impliciti nei costruttori di classi?
Domanda
C# non richiede di specificare un parametro di tipo generico se il compilatore può dedurlo, ad esempio:
List<int> myInts = new List<int> {0,1,1,
2,3,5,8,13,21,34,55,89,144,233,377,
610,987,1597,2584,4181,6765};
//this statement is clunky
List<string> myStrings = myInts.
Select<int,string>( i => i.ToString() ).
ToList<string>();
//the type is inferred from the lambda expression
//the compiler knows that it's taking an int and
//returning a string
List<string> myStrings = myInts.
Select( i => i.ToString() ).
ToList();
Ciò è necessario per i tipi anonimi in cui non sai quale sarebbe il parametro di tipo (in Intellisense appare come 'a
) perché viene aggiunto dal compilatore.
I parametri di tipo a livello di classe non ti consentono di fare ciò:
//sample generic class
public class GenericDemo<T>
{
public GenericDemo ( T value )
{
GenericTypedProperty = value;
}
public T GenericTypedProperty {get; set;}
}
//why can't I do:
int anIntValue = 4181;
var item = new GenericDemo( anIntValue ); //type inference fails
//however I can create a wrapper like this:
public static GenericDemo<T> Create<T> ( T value )
{
return new GenericDemo<T> ( value );
}
//then this works - type inference on the method compiles
var item = Create( anIntValue );
Perché C# non supporta questa inferenza di tipo generico a livello di classe?
Soluzione
In realtà la tua domanda non è male.Ho giocato con un linguaggio di programmazione generico negli ultimi anni e anche se non sono mai riuscito a svilupparlo effettivamente (e probabilmente non lo farò mai), ho pensato molto all'inferenza di tipo generico e una delle mie massime priorità è è sempre stato quello di consentire la costruzione di classi senza dover specificare il tipo generico.
C# semplicemente non dispone dell'insieme di regole per renderlo possibile.Penso che gli sviluppatori non abbiano mai visto la necessità di includerlo.In realtà, il seguente codice sarebbe molto vicino alla tua proposta e risolverebbe il problema.Tutto ciò di cui C# ha bisogno è un ulteriore supporto per la sintassi.
class Foo<T> {
public Foo(T x) { … }
}
// Notice: non-generic class overload. Possible in C#!
class Foo {
public static Foo<T> ctor<T>(T x) { return new Foo<T>(x); }
}
var x = Foo.ctor(42);
Dato che questo codice funziona davvero, abbiamo dimostrato che il problema non è di semantica ma semplicemente di mancanza di supporto.Immagino di dover riprendere il mio intervento precedente.;-)
Altri suggerimenti
Perché C# non supporta questa inferenza di tipo generico a livello di classe?
Perché generalmente sono ambigui.Al contrario, l'inferenza del tipo è banale per le chiamate di funzione (se tutti i tipi compaiono negli argomenti).Ma nel caso delle chiamate al costruttore (funzioni glorificate, per amore di discussione), il compilatore deve risolvere più livelli contemporaneamente.Un livello è il livello della classe e l'altro è il livello degli argomenti del costruttore.Credo che risolverlo sia algoritmicamente non banale.Intuitivamente, direi che è addirittura NP-completo.
Per illustrare un caso estremo in cui la risoluzione è impossibile, immagina la seguente classe e dimmi cosa dovrebbe fare il compilatore:
class Foo<T> {
public Foo<U>(U x) { }
}
var x = new Foo(1);
Grazie Konrad, è una buona risposta (+1), ma solo per approfondire l'argomento.
Facciamo finta che C# abbia una funzione di costruzione esplicita:
//your example
var x = new Foo( 1 );
//becomes
var x = Foo.ctor( 1 );
//your problem is valid because this would be
var x = Foo<T>.ctor<int>( 1 );
//and T can't be inferred
Hai perfettamente ragione nel dire che il primo costruttore non può essere dedotto.
Ora torniamo alla classe
class Foo<T>
{
//<T> can't mean anything else in this context
public Foo(T x) { }
}
//this would now throw an exception unless the
//typeparam matches the parameter
var x = Foo<int>.ctor( 1 );
//so why wouldn't this work?
var x = Foo.ctor( 1 );
Naturalmente, se aggiungo nuovamente il tuo costruttore (con il suo tipo alternativo) abbiamo una chiamata ambigua, esattamente come se non fosse possibile risolvere un normale sovraccarico del metodo.