2009-10-22 6 views
10

Je me demandais si ce qui suit est possible. Créez une classe qui accepte un type anonyme (string, int, decimal, customObject, etc.), puis ajoutez des méthodes surchargées qui effectuent différentes opérations en fonction du type. ExempleMéthode de surcharge avec les types 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  
    } 

} 

Alors maintenant, je pourrais appeler la méthode GetName, et parce que je l'ai déjà passé dans le type quand j'initialisé l'objet, la méthode correcte est trouvée et exécuté.

TestClass foo = new TestClass<int>(); 

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

Est-ce possible ou est-ce que je viens de rêver?

Répondre

12

Qu'est-ce que vous essayez de faire est possible comme ceci:

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

Bien que cette est possible, vous êtes un peu le but de vaincre les médicaments génériques. Le point de génériques est lorsque le type ne importe pas, donc je ne pense pas que les génériques est approprié dans ce cas.

0

L'utilisation de méthodes d'extension de classe vous convient-elle?

Vous pouvez essentiellement ajouter des méthodes aux classes que vous voulez, et vous pouvez ensuite l'appeler de la même manière.

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

appelé à l'aide:

myString.GetName(); 
4

"spécialisation" n'est pas possible en C# la façon dont il est en C++. Dans les génériques .NET, une classe ou méthode générique de <T> doit être la même pour toutes les valeurs possibles de T. Cela permet au moteur d'exécution d'effectuer une optimisation selon deux types de référence différents, par exemple TestClass < chaîne > et TestClass < Liste <int> >, partagent le même code de langage machine. (Différents types de valeur obtenir le code de machine séparée, mais vous ne pouvez toujours pas se spécialiser.)

Je trouve cela permet parfois de créer une interface générique ou classe de base comme celui-ci:

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

Et faire une spécialisation en dérivés Classes:

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 Génériques! = Modèles – user7116

1

Non, ce n'est pas possible. Ce que vous essayez de faire est similaire à la spécialisation de template en C++, ce qui n'est (malheureusement) pas possible en C#.

Vous devez if/else ou un commutateur sur

typeof(T) 

pour appeler des implémentations spécialisées.

Cependant, vous pouvez contrainte le type de T pour être une (valeur) classe (valeur de référence) ou struct ou sous-classe d'une certaine classe de base comme ceci:

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

C# ne prend pas en charge pour un tel envoi.

(Error'TestClass 'définit déjà un membre appelé' GetName 'avec les mêmes types de paramètres) tant que <> ne fait pas partie de la signature de la méthode.

3

La spécialisation n'est pas possible en C#. La chose la plus proche en C# est le

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

suivant le compilateur C# préférera une méthode non-générique sur une méthode générique. Cela signifie que l'appel avec un paramètre int se liera à la surcharge int contre la surcharge générique.

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

Cela vous mordre mais parce que cela ne vaut pas lorsque la méthode est appelée génériquement. Dans ce cas, il se liera à la surcharge générique, peu importe le type.

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

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

Si vous devez effectuer un travail spécifique à votre classe, votre classe n'est pas générique. Vous devriez probablement créer une classe séparée pour chaque type que vous voulez gérer. S'il y a une fonctionnalité qui a une bonne raison d'être générique, vous pouvez la mettre dans une classe de base commune.

Un exemple:

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

Comme mentionné Bfree vous pouvez le faire avec un si arbre, ou plus probablement une instruction switch, mais à un moment donné vous souhaiterez vous pouvez simplement écrire des méthodes et laisser .Net comprendre, surtout si vous développez la bibliothèque de surcharges au fil du temps.

La solution il y a une réflexion, mais il est assez sage performance pas cher en .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; 
} 

Vous êtes fondamentalement juste dire le cadre de réflexion pour aller faire cette déclaration de commutation pour vous.

Questions connexes