2009-10-22 4 views
10

Мне было интересно, возможно ли следующее. Создайте класс, который принимает анонимный тип (строка, int, decimal, customObject и т. Д.), А затем перегруженные методы, которые выполняют разные операции на основе типа. ПримерПерегрузка метода с помощью типов 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  
    } 

} 

Так что теперь я мог бы вызвать метод GetName, и потому что я уже проходил в типе, когда я инициализируюсь объект, правильный метод будет найден и казнен.

TestClass foo = new TestClass<int>(); 

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

Возможно ли это, или я просто мечтаю?

ответ

12

То, что вы пытаетесь сделать, это можно так:

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

Хотя это является возможно, вы своего рода поражение цели дженериков. Точка дженериков - это когда тип не имеет значения, поэтому я не думаю, что в этом случае подходят дженерики.

0

Будут ли использоваться методы расширения класса?

Вы можете существенно добавить методы к классам, которые хотите, а затем вы можете называть их одинаково.

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

вызывается с помощью:

myString.GetName(); 
4

"Специализация" не возможно в C#, как она находится в C++. В обобщенных стандартах .NET общий класс или метод <T> должен быть одинаковым для всех возможных значений T. Это позволяет среде выполнения выполнять оптимизацию, которая состоит из двух разных типов ссылок, например, TestClass < строка > и TestClass < Список <int> >, использовать один и тот же код машинного языка. (Различные типы значений получить отдельный машинный код, но вы до сих пор не могут специализироваться.)

Я считаю, что иногда помогает создать общий интерфейс или базовый класс вроде этого:

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

И сделать специализацию в полученных классы:

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! = Шаблоны – user7116

1

Нет, это невозможно. То, что вы пытаетесь сделать, похоже на специализированную специализацию на C++, которая (к сожалению) невозможна в C#.

Вам нужно, если/другое или переключатель на

typeof(T) 

для вызова специализированных реализаций.

Однако, вы можете тяготы типа Т быть либо класс (справочное значение) или структуру (значение) или подкласс определенного BaseClass так:

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

C# не имеет поддержки такая отправка.

и это неправильный способ для перегрузки метода также (Error'TestClass уже определяет член, называемый «GetName» с теми же параметрами), если все внутри <> не является частью сигнатуры метода.

3

Специализация невозможна в C#. Самая близкая вещь в C# является следующая

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

C# компилятор предпочтет, не универсальный метод более общий метод. Это означает, что вызов с int paramater будет привязан к перегрузке int по сравнению с общим.

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

Это укусит вас, хотя это не применяется, когда метод вызывается в общем случае. В этом случае он будет привязан к общей перегрузке независимо от типа.

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

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

Если вам нужно выполнить работу по конкретному типу в своем классе, то ваш класс не является общим. Вероятно, вы должны сделать отдельный класс для каждого типа, который вы хотите обработать. Если есть какая-то функциональность, которая имеет правильную причину для генерации, вы можете поместить ее в общий базовый класс.

Пример:

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

Как BFree упоминалось вы можете сделать это с помощью, если дерево, или, скорее, переключатель заявление, но в какой-то момент вы хотите вы могли бы просто написать методы и пусть .Net выясните это, особенно если вы увеличите библиотеку перегрузок с течением времени.

Решения есть отражение, хотя это довольно дешево производительность мудрое в .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; 
} 

Вы в основном просто говорите рамку Reflection пойти и сделать что переключатель заявление для вас.

Смежные вопросы