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?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top