2012-12-22 6 views
9

Eric Lippert ha spiegato nel suo post sul blog al http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx perché i vincoli non sono considerati per l'inferenza di tipo, il che ha senso dato che i metodi non possono essere sovraccaricati semplicemente cambiando i vincoli di tipo. Tuttavia, mi piacerebbe trovare un modo per creare un'istanza di un oggetto utilizzando due tipi generici, uno che può essere dedotto e un altro che può essere dedotto se sono stati considerati i vincoli, senza dover specificare nessuno dei tipi.C'è una soluzione alternativa a C# che non è in grado di dedurre argomenti di tipo generico usando i vincoli di tipo?

Dati i tipi:

public interface I<T> 
{ 
    Other<T> CreateOther(); 
} 

public class C : I<string> 
{ 
    public Other<string> CreateOther() 
    { 
     return new Other<string>(); 
    } 
} 

public class Other<T> 
{ 
} 

e la fabbrica:

public static class Factory1 
{ 
    public static Tuple<T, Other<T1>> Create<T, T1>(T o) where T : I<T1> 
    { 
     return new Tuple<T, Other<T1>>(o, o.CreateOther()); 
    } 
} 

il seguente codice desiderato non viene compilato:

messaggio
public void WontCompile() 
    { 
     C c = new C(); 
     var v = Factory1.Create(c); // won't compile 
    } 

L'errore è "CS0411 Errore: il digitare argomenti per il metodo 'yo.Factory1.Create (T)' non può essere dedotto dall'utilizzo. Prova a specificare il tipo a rguments esplicitamente. ", che è in linea con ciò che Eric ha detto nel suo post sul blog.

Così, si può semplicemente specificare gli argomenti di tipo generico in modo esplicito, come il messaggio di errore suggerisce:

public void SpecifyAllTypes() 
    { 
     C c = new C(); 
     var v = Factory1.Create<C, string>(c); // type is Tuple<C, Other<string>> 
    } 

Se non vogliamo specificare argomenti di tipo e non abbiamo bisogno di mantenere il tipo C, siamo in grado di utilizzare il seguente fabbrica:

public static class Factory2 
{ 
    public static Tuple<I<T1>, Other<T1>> CreateUntyped<T1>(I<T1> o) 
    { 
     return new Tuple<I<T1>, Other<T1>>(o, o.CreateOther()); 
    } 
} 

e ora specificare:

public void Untyped() 
    { 
     C c = new C(); 
     var v = Factory2.CreateUntyped(c); // type is Tuple<I<string>, Other<string>> 
    } 

Ho Comunque, desidero mantenere il tipo C nell'oggetto restituito e non specificare i tipi.

risposta

4

Mi è venuta una soluzione a questo problema, ma sembra essere un trucco di una soluzione, in cui l'oggetto di tipo C viene utilizzato due volte in una chiamata di fabbrica in due fasi.

Per fare questo, i seguenti stabilimenti sono utilizzati:

public static class Factory3 
{ 
    public static Factory<T1> CreateFactory<T1>(I<T1> o) 
    { 
     return new Factory<T1>(); 
    } 
} 

public class Factory<T1> 
{ 
    public Tuple<T, Other<T1>> Create<T>(T o) where T : I<T1> 
    { 
     return new Tuple<T, Other<T1>>(o, o.CreateOther()); 
    } 
} 

che può quindi essere utilizzato come segue:

public void Inferred() 
    { 
     C c = new C(); 
     var v = Factory3.CreateFactory(c).Create(c); // type is Tuple<C, Other<string>> 
    } 

Questo si sente proprio strano dato che c è usato due volte. La prima volta che viene utilizzato, viene effettivamente scartato poiché viene utilizzato per dedurre l'argomento del tipo di base.

Esiste una soluzione migliore a questo problema in cui l'oggetto non deve essere utilizzato due volte e non è necessario specificare i tipi?

modifica: Ho appena realizzato che, sebbene l'oggetto debba essere utilizzato due volte, la seconda classe di fabbrica non è necessaria.Piuttosto, entrambi i parametri possono solo essere utilizzati con lo stesso metodo fabbrica come segue:

public class Factory 
{ 
    public Tuple<T, Other<T1>> Create<T, T1>(T o, I<T1> o2) where T : I<T1> 
    { 
     return new Tuple<T, Other<T1>>(o, o.CreateOther()); 
    } 
} 

Questo sarebbe stato utilizzato come segue:

public void Inferred() 
{ 
    C c = new C(); 
    var v = Factory.Create(c, c); // type is Tuple<C, Other<string>> 
} 

E 'ancora non è l'ideale, ma meglio di dover creare un secondo classe factory, e almeno commenti XMLDoc potrebbero essere usati per indicare che entrambi i parametri dovrebbero essere lo stesso oggetto. Ancora una volta, l'unico parametro (o2 in questo caso) viene utilizzato solo per dedurre i tipi vincolati per T.

Problemi correlati