Sobrecarga de método com tipos C #
-
05-07-2019 - |
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?
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 >, 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ê.