2009-10-22 17 views
10

Me preguntaba si lo siguiente es posible. Cree una clase que acepte un tipo anónimo (cadena, int, decimal, customObject, etc.) y luego tenga métodos sobrecargados que realicen diferentes operaciones basadas en el tipo. EjemploMétodo de sobrecarga con los tipos 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  
    } 

} 

Así que ahora podría llamar al método GetName, y porque ya pasé en el tipo cuando inicializa el objeto, se encuentra el método correcto y ejecutado.

TestClass foo = new TestClass<int>(); 

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

¿Es esto posible o solo estoy soñando?

Respuesta

12

Lo que estamos tratando de hacer es posible de esta manera:

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

Si bien esto es posible, estás tipo de derrotar el propósito de los genéricos. El punto de los genéricos es cuando el tipo no importa, así que no creo que los genéricos sean apropiados en este caso.

0

¿Funcionarían los métodos de extensión de clase para usted?

Básicamente, puede agregar métodos a las clases que desee y, a continuación, puede llamarlo de la misma manera.

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

llamada usando:

myString.GetName(); 
4

"especialización" no es posible en C# de la manera que está en C++. En los genéricos de .NET, una clase genérica o método de <T> deben ser los mismos para todos los valores posibles de T. Esto permite que el tiempo de ejecución para hacer una optimización que dos tipos diferentes de referencia, dicen TestClass <cadena> y TestClass < Lista <int> >, comparta el mismo código de idioma de la máquina. (Diferentes tipos de valor obtienen código de máquina por separado, pero aún así no pueden especializarse.)

me resulta a veces ayuda a crear una interfaz genérica o una clase de base de la siguiente manera:

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

Y hacer la especialización en derivados clases:

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

1

No, esto no es posible. Lo que intenta hacer es similar a la especialización de plantilla en C++, que (lamentablemente) no es posible en C#.

Necesitas if/else o switch en

typeof(T) 

para invocar implementaciones especializadas.

Sin embargo, puede restricción del tipo de T para ser una clase (valor de referencia) o estructura (valor) o subclase de una determinada clase base, así:

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

C# no tiene soporte para tal despacho.

y esto no es la forma correcta para hacer la sobrecarga de métodos también (Error'TestClass' ya define un miembro llamado 'GetName' con los mismos tipos de parámetros), siempre y cuando todo el interior <> no es una parte de la firma método.

3

La especialización no es posible en C#. Lo más parecido en C# es la siguiente

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

el compilador de C# preferirá un método no genérico sobre un método genérico. Esto significa que la llamada con un int paramater se vinculará a la sobrecarga int vs. la genérica.

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

Aunque esto no lo hará porque esto no se aplica cuando se llama genéricamente al método. En ese caso, se vinculará a la sobrecarga genérica sin importar el tipo.

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

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

Si necesita hacer un trabajo de tipo específico en su clase, su clase no es genérica. Probablemente deberías hacer una clase separada para cada tipo que quieras manejar. Si hay alguna funcionalidad que tenga una razón adecuada para ser genérica, puede ponerla en una clase base común.

Un ejemplo:

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

Como se mencionó bfree se puede hacer esto con un árbol de si, o más probablemente una sentencia switch, pero en algún momento le deseo a usted podría escribir métodos y dejar .Net descárgalo, especialmente si creces la biblioteca de sobrecargas con el tiempo.

La solución hay reflexión, aunque es bastante barato en cuanto al rendimiento 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; 
} 

Básicamente, se está simplemente diciendo el marco de reflexión para ir a hacer que la instrucción switch para usted.

Cuestiones relacionadas