2013-07-11 16 views
25

Diciamo che ho questo tipo di interfaccia e l'attuazione concretaInterfaccia con parametro generico vs Interfaccia con metodi generici

public interface IMyInterface<T> 
{ 
    T My(); 
} 

public class MyConcrete : IMyInterface<string> 
{ 
    public string My() 
    { 
     return string.Empty; 
    } 
} 

Così ho creare implementazione MyConcrete per strings, posso avere un altro implementazione concreta per int. E va bene Ma diciamo che io voglio fare la stessa cosa, ma con metodi generici, quindi devo

public interface IMyInterface2 
{ 
    T My<T>(); 
} 

public class MyConcrete2 : IMyInterface2 
{ 
    public string My<string>() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Così mi hanno lo stesso IMyInterface2, ma che definisce il comportamento generico mediante T My<T>(). Nella mia classe concreta voglio implementare il comportamento My, ma per il tipo di dati concreti - string. Ma C# non mi consente di farlo.

La mia domanda è perché non posso farlo? In altre parole, se posso creare un'implementazione concreta di MyInterface<T> come MyClass : MyInterface<string> e interrompere genericità a questo punto, perché non posso farlo con il metodo generico - T My<T>()?

+1

Non è possibile * ridurre * le abilità quando si ereditano i tipi, è possibile solo aggiungerle. –

risposta

29

L'implementazione metodo generico deve essere generico come bene, quindi deve essere:

public class MyConcrete2 : IMyInterface2 
{ 
    public T My<T>() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Perché non si può fare My<string>() qui? Perché il contratto di interfaccia richiede un metodo, che può essere chiamato con qualsiasi parametro di tipo T e devi soddisfare tale contratto.

Perché non è possibile arrestare genericità in questo punto? perché causerebbe situazioni come segue:

dichiarazioni di classe:

public interface IMyInterface2 
{ 
    T My<T>(t value); 
} 

public class MyClass21 : IMyInterface2 
{ 
    public string My<string>(string value) { return value; } 
} 

public class MyClass22 : IMyInterface2 
{ 
    public int My<int>(int value) { return value; } 
} 

Usage:

var item1 = new MyClass21(); 
var item2 = new MyClass22(); 

// they both implement IMyInterface2, so we can put them into list 
var list = new List<IMyInterface2>(); 
list.Add(item1); 
list.Add(item2); 

// iterate the list and call My method 
foreach(IMyInterface2 item in list) 
{ 
    // item is IMyInterface2, so we have My<T>() method. Choose T to be int and call with value 2: 
    item.My<int>(2); 

    // how would it work with item1, which has My<string> implemented? 
} 
+1

Ha bisogno di essere pubblico 'T My ()' –

+0

se posso creare concreta attuazione MyInterface come MyClass: MyInterface e fermare genericità in questo punto, perché non posso farlo con metodo generico - t My ()? –

+1

@JevgenijNekrasov Controlla il mio aggiornamento. Ho mostrato una situazione in cui l'implementazione 'My ' non funzionava. – MarcinJuraszek

0

Poiché l'interfaccia dichiara un metodo generico T My<T>(), ma l'attuazione non lo fa implementare una funzione con quella specifica firma.

per ottenere ciò che si desidera, è necessario fornire il parametro generico T per l'interfaccia, invece, nel primo esempio:

public interface IMyInterface2<T> 
{ 
     T My(); 
} 

public class MyConcrete2 : IMyInterface2<string> 
{ 
    public string My() 
    { 
     throw new NotImplementedException(); 
    } 
} 
+0

So come ottenere ciò che voglio, voglio sapere perché non riesco a fermare la genericità come posso fare con le interfacce –

2

quando si scrive il metodo generico la definizione è per mantenere il segnaposto. Il tipo effettivo entra in figura quando si chiama il metodo. quindi invece dovresti scrivere

public T My<T>() 
{ 
    throw new NotImplementedException(); 
} 

e quando chiami il metodo puoi usare la stringa lì.

+0

Voglio interrompere generecness come posso fare con l'interfaccia generica, ad es. MyClass: MyInterface

0

La soluzione non funziona per due motivi.

In primo luogo, un'interfaccia è un contratto. Quando si implementa IMyInterface2, si garantisce l'implementazione di una funzione denominata My che accetta un parametro di tipo generico e restituisce tale tipo. MyConcrete2 non lo fa.

In secondo luogo, i generici C# non consentono alcun tipo di specializzazione dei parametri di tipo. (Desidero che C# sia supportato da questo.) Questa è una cosa comune nei modelli C++ in cui il tuo esempio verrebbe compilato, ma qualsiasi utilizzo di MyConcrete2 non riuscirebbe a compilare se non chiamano My con un string.

Problemi correlati