Pergunta

Eu queria saber se o seguinte é possível. Crie uma classe que aceita um tipo anônimo (string, int, decimal, customObject, etc), métodos, em seguida, ter sobrecarregados que fazem operações diferentes com base no tipo. Exemplo

    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    
  }

}

Então, agora eu poderia chamar o método GetName, e porque eu já passou no tipo quando inicializado o objeto, o método correto é encontrado e executado.

TestClass foo = new TestClass<int>();

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

Isso é possível ou estou apenas sonhando?

Foi útil?

Solução

O que você está tentando fazer é possível, como este:

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

Embora este é possível, você está tipo de derrotar o efeito dos genéricos. O ponto de genéricos é quando o tipo não assunto, então eu não acho que os genéricos é apropriado neste caso.

Outras dicas

A especialização não é possível em C #. A coisa mais próxima em C # é o seguinte

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

O compilador C # vai preferir um método não-genérico ao longo de um método genérico. Isto significa que chama com uma paramater int irá ligar-se à sobrecarga int versus a um genérico.

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

Isto irá mordê-lo, porque embora isto não se aplica quando o método é chamado genericamente. Nesse caso, ele vai ligar à sobrecarga genérica Não importa o tipo.

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

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

"Especialização" não é possível em C # do jeito que está em C ++. Em genéricos .NET, uma classe genérica ou método de deve ser o mesmo para todos os valores possíveis de T. Isso permite que o tempo de execução para fazer uma otimização que dois tipos de referência diferentes, dizem TestClass e TestClass >, partilham o mesmo código de linguagem de máquina. (Tipos de valor diferente obter o código de máquina separada, mas você ainda não pode se especializar.)

Acho que é, por vezes, ajuda a criar uma interface genérica ou classe base como esta:

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

E fazer especialização em classes derivadas:

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

Não, isso não é possível. O que você está tentando fazer é semelhante à especialização de modelo em C ++, que é (infelizmente) não é possível em C #.

Você precisa if / else ou switch on

typeof(T)

para invocar implementações especializadas.

No entanto, você pode restrição do tipo de T para ser uma classe (valor de referência) ou struct (valor) ou subclasse de uma determinada baseclass assim:

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

c # não tem suporte para a expedição.

e este não é o caminho certo para fazer método de sobrecarga também (Error'TestClass' já define um membro do chamado 'GetName' com os mesmos tipos de parâmetros), desde que todos dentro de <> não é uma parte da assinatura do método.

Would métodos usando extensão de classe trabalhar para você?

Você pode essencialmente adicionar métodos às classes que você quer, e então você pode chamá-lo da mesma forma.

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

chamado usando:

myString.GetName();

Se você precisar fazer um trabalho específico do tipo em sua classe, em seguida, sua classe não é genérico. Você provavelmente deve fazer uma classe separada para cada tipo que você deseja manipular. Se há alguma funcionalidade que tem uma razão adequada para ser genérico, você pode colocá-lo em uma classe base comum.

Um exemplo:

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
}

Como BFree mencionado você pode fazer isso com um caso árvore, ou, mais provavelmente uma instrução switch, mas em algum momento você vai desejar que você poderia métodos Basta escrever e deixe figura Net-lo, especialmente se você crescer a biblioteca de sobrecargas ao longo do tempo.

A solução existe reflexão, embora seja muito mais barato em termos de performance em .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;
}

Você está basicamente dizendo ao quadro reflexão para ir fazer isso instrução switch para você.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top