2009-10-22 9 views
10

Ich fragte mich, ob das Folgende möglich ist. Erstellen Sie eine Klasse, die einen anonymen Typ akzeptiert (string, int, dezimal, customObject usw.), und überladen Sie dann Methoden, die auf Grundlage des Typs verschiedene Operationen ausführen. BeispielMethode überladen mit Typen 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  
    } 

} 

So, jetzt konnte ich die GetName-Methode aufrufen, und weil ich schon in der Art übergeben, wenn ich das Objekt initialisiert, wird die richtige Methode gefunden und ausgeführt.

TestClass foo = new TestClass<int>(); 

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

Ist das möglich oder träume ich nur?

Antwort

12

Was Sie versuchen zu tun, wie folgt aus:

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

Während diese möglich ist, sind Sie Art von dem Zweck der Generika zu besiegen. Der Punkt der Generika ist, wenn der Typ nicht spielt, also glaube ich nicht, dass Generika in diesem Fall geeignet sind.

0

Würden Klassenerweiterungsmethoden für Sie arbeiten?

Sie können Methoden zu den gewünschten Klassen hinzufügen, und dann können Sie es auf die gleiche Weise aufrufen.

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

namens:

myString.GetName(); 
4

"Spezialisierung" ist in C# nicht möglich, wie es in C++. In .NET-Generics muss eine generische Klasse oder Methode <T> für alle möglichen Werte von T identisch sein. Dies ermöglicht der Laufzeitumgebung, eine Optimierung für zwei unterschiedliche Referenztypen durchzuführen, z. B. TestClass <String> und TestClass < Liste <int> >, teilen Sie den gleichen Maschinensprachcode. (Verschiedene Werttypen separaten Maschinencode, aber man kann immer noch nicht gehört.)

Ich finde es hilft manchmal eine generische Schnittstelle oder Basisklasse wie diese zu erstellen:

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

und Spezialisierung tun in abgeleiteten Klassen:

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! = Vorlagen – user7116

1

Nein, das ist nicht möglich. Was Sie versuchen, ist ähnlich der Template-Spezialisierung in C++, was in C# (leider) nicht möglich ist.

Sie müssen if/else oder Schalter auf

typeof(T) 

spezialisierte Implementierungen aufzurufen.

Sie können jedoch die Art des T Zwang entweder eine Klasse (Referenzwert) oder Struktur (Wert) oder Unterklasse eines bestimmten Basisklasse zu sein, etwa so:

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

C# hat keine Unterstützung für solche Absendung.

und dies ist nicht der richtige Weg für das Überladen von Methoden (Error'TestClass 'definiert bereits ein Element namens' GetName 'mit den gleichen Parametertypen), solange alle innerhalb <> nicht Teil der Methodensignatur sind.

3

Spezialisierung ist in C# nicht möglich. Die nächste Sache in C# ist die folgende

Der C# -Compiler wird eine nicht-generische Methode gegenüber einer generischen Methode bevorzugen. Dies bedeutet, dass der Aufruf mit einem int-Parameter an die Int-Überladung im Vergleich zum generischen bindet.

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

Dies wird Sie beißen, weil dies nicht gilt, wenn die Methode generisch aufgerufen wird. In diesem Fall wird es unabhängig vom Typ an die generische Überladung gebunden.

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

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

Wenn Sie typspezifische Arbeit in Ihrer Klasse ausführen müssen, dann ist Ihre Klasse nicht generisch. Sie sollten wahrscheinlich eine separate Klasse für jeden Typ erstellen, den Sie behandeln möchten. Wenn es einige Funktionen gibt, die einen angemessenen Grund haben, generisch zu sein, können Sie sie in eine gemeinsame Basisklasse einfügen.

Ein Beispiel:

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

Wie BFree erwähnt Sie dies, wenn Baum mit einem tun, oder eher eine switch-Anweisung, aber irgendwann werden Sie wollen Sie nur Methoden schreiben könnte und lassen .Net finde es heraus, besonders wenn du die Bibliothek der Überladungen im Laufe der Zeit erweiterst.

Die Lösung gibt Reflexion ist, obwohl es ziemlich billig leistungsmäßig in .Net ist:

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; 
} 

Sie sind im Grunde nur die Reflexion Rahmen zu sagen für Sie, dass switch-Anweisung zu gehen zu tun.