2009-10-22 10 views
10

Mi chiedevo se quanto segue è possibile. Crea una classe che accetta un tipo anonimo (string, int, decimal, customObject, ecc.), Quindi applica metodi di overload che eseguono operazioni diverse in base al tipo. EsempioSovraccarico del metodo con i tipi C#

class TestClass<T> 
{ 
    public void GetName<string>() 
    { 
     //do work knowing that the type is a string  
    } 

    public string GetName<int>() 
    { 
     //do work knowing that the type is an int 

    } 

    public string GetName<int>(int addNumber) 
    { 
     //do work knowing that the type is an int (overloaded)  
    } 

    public string GetName<DateTime>() 
    { 
     //do work knowing that the type is a DateTime 

    } 

    public string GetName<customObject>() 
    { 
     //do work knowing that the type is a customObject type  
    } 

} 

Così ora ho potuto chiamare il metodo GetName, e perché ho già passato nel tipo quando ho inizializzato l'oggetto, il metodo corretto viene trovato e giustiziato.

TestClass foo = new TestClass<int>(); 

//executes the second method because that's the only one with a "int" type 
foo.GetName(); 

È possibile o sto solo sognando?

metodi

risposta

12

cosa si sta cercando di fare è possibile in questo modo:

class TestClass<T> 
{ 
    public string GetName<T>() 
    { 
     Type typeOfT = typeof(T); 
     if(typeOfT == typeof(string)) 
     { 
      //do string stuff 
     } 
    } 
} 

Mentre questo è possibile, si sta sorta di sconfiggere lo scopo di farmaci generici. Il punto di generici è quando il tipo non è lo, quindi non credo che i generici siano appropriati in questo caso.

0

Would estensione utilizzando la classe lavorare per voi?

È possibile essenzialmente aggiungere metodi alle classi che si desidera, e quindi si può chiamare allo stesso modo.

namespace ExtensionMethods 
{ 
    public static class MyExtensions 
    { 
     public static int GetName(this String str) 
     { 
      ... 
     } 
    } 
} 

chiamata utilizzando:

myString.GetName(); 
4

"specializzazione" non è possibile in C# il modo in cui è in C++. In generics .NET, una classe generica o un metodo di <T> deve essere uguale per tutti i possibili valori di T. Ciò consente al runtime di eseguire un'ottimizzazione di due tipi di riferimento diversi, ad esempio TestClass <stringa> e TestClass < Elenco <int> >, condividere lo stesso codice lingua macchina. (Diversi tipi di valore ottenere il codice macchina separata, ma ancora non possono specializzarsi.)

trovo a volte aiuta a creare un'interfaccia generica o classe di base in questo modo:

abstract class Base<T> { 
    public abstract T GetName(); 
    // any common code goes here that does not require specialization 
} 

E fare la specializzazione in derivati classi:

class IntVersion : Base<int> { 
    public override int GetName() { return 1; } 
    public int GetName(int addNumber) { ... } 
} 
class StringVersion : Base<string> { 
    public override string GetName() { return "foo"; } 
} 
class DateTimeVersion : Base<DateTime> { 
    public override DateTime GetName() { return DateTime.Now; } 
} 
+0

+1 Generics! = Modelli – user7116

1

No, questo non è possibile. Quello che stai cercando di fare è simile alla specializzazione dei template in C++, che è (purtroppo) non possibile in C#.

È necessario if/else o accendere

typeof(T) 

per invocare implementazioni specializzate.

Tuttavia, è possibile vincolo del tipo di T essere o una classe (valore di riferimento) o struct (valore) o sottoclasse di un certo baseclass in questo modo:

public Foo<T> DoBar<T>() where T : FooBase; 
0

C# non ha il supporto per tale dispacciamento.

e questo non è il modo giusto per eseguire il overloading del metodo anche (Error'TestClass 'definisce già un membro chiamato' GetName 'con gli stessi tipi di parametri) purché tutto all'interno di <> non sia una parte della firma del metodo.

3

La specializzazione non è possibile in C#. La cosa più vicina in C# è la seguente

public void Example() { 
    public static void Method<T>(T value) { ... } 
    public static void Method(int value){ ... } 
    public static void Method(string) { ... } 
} 

Il compilatore C# preferisce un metodo non generico su un metodo generico. Ciò significa che la chiamata con un parametro int si collegherà al sovraccarico int rispetto a quello generico.

Example.Method(42); // Method(int) 
Example.Method(new Class1()) // Method<T>(T) 

Questo ti morderà anche perché questo non si applica quando il metodo è chiamato genericamente. In tal caso si vincolerà al sovraccarico generico indipendentemente dal tipo.

public void Gotcha<T>(T value) { 
    Example.Method(value); 
} 

Gotcha(42); // Still calls Example.Method<T>() 
0

Se avete bisogno di fare tipo specifico di lavoro nella tua classe, allora la classe non è generica. Probabilmente dovresti creare una classe separata per ogni tipo che vuoi gestire. Se c'è qualche funzionalità che ha una ragione adeguata per essere generica, puoi metterla in una classe base comune.

Un esempio:

abstract class TestClass<T> 
{ 
    public List<T> Items { get; set; } 

    // other generic (i.e. non type-specific) code 
} 

class IntTestClass : TestClass<int> 
{ 
    public string GetName() 
    { 
     // do work knowing that the type is an int 
    } 

    // other code specific to the int case 
} 

class StringTestClass : TestClass<string> 
{ 
    public string GetName() 
    { 
     // do work knowing that the type is a string 
    } 

    // other code specific to the string case 
} 
0

Come BFree detto che si può fare questo con un albero di se, o più probabilmente di un'istruzione switch, ma ad un certo punto ti desidera si può solo scrivere metodi e lasciare .Net capirlo, soprattutto se si aumenta la libreria di sovraccarichi nel tempo.

La soluzione c'è riflessione, anche se è piuttosto a buon mercato prestazioni-saggio in .Net:

using System.Reflection; 
... 

public string DoSomething(object val) 
{ 
    // Force the concrete type 
    var typeArgs = new Type[] { val.GetType() }; 

    // Avoid hard-coding the overloaded method name 
    string methodName = new Func<string, string>(GetName).Method.Name; 

    // Use BindingFlags.NonPublic instead of Public, if protected or private 
    var bindingFlags = BindingFlags.Public | BindingFlags.Instance; 

    var method = this.GetType().GetMethod(
     methodName, bindingFlags, null, typeArgs, null); 

    string s = (string)method.Invoke(this, new object[] { val }); 

    return s; 
} 

Stai fondamentalmente solo dicendo il quadro di riflessione per andare a fare questa affermazione interruttore per voi.

Problemi correlati