Мне было интересно, возможно ли следующее. Создайте класс, который принимает анонимный тип (строка, int, decimal, customObject и т.д.), А затем перегруженные методы, которые выполняют разные операции на основе типа. Пример
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 the only one with a "int" type
foo.GetName();
Возможно ли это, или я просто мечтаю?
Ответ 1
То, что вы пытаетесь сделать, возможно следующим образом:
class TestClass<T>
{
public string GetName<T>()
{
Type typeOfT = typeof(T);
if(typeOfT == typeof(string))
{
//do string stuff
}
}
}
В то время как это возможно, вы как бы побеждаете цель дженериков. Точка дженериков - это когда тип не имеет значения, поэтому я не думаю, что в этом случае подходящими являются дженерики.
Ответ 2
"Специализация" на С# невозможна, как в С++. В генерических файлах .NET общий класс или метод <T> должно быть одинаковым для всех возможных значений T. Это позволяет среде выполнения оптимизировать два разных типа ссылок, например TestClass <string> и TestClass < List <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; }
}
Ответ 3
В С# специализация невозможна. Самая близкая вещь в С# следующая
public void Example() {
public static void Method<T>(T value) { ... }
public static void Method(int value){ ... }
public static void Method(string) { ... }
}
Компилятор С# предпочтет не общий метод для общего метода. Это означает, что вызов с 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>()
Ответ 4
Нет, это невозможно. То, что вы пытаетесь сделать, похоже на специализированную специализацию на С++, которая (к сожалению) невозможна в С#.
Вам нужно, если /else или включить
typeof(T)
для вызова специализированных реализаций.
Тем не менее, вы можете ограничить тип T либо классом (ссылочным значением), либо структурой (значением) или подклассом определенного базового слова следующим образом:
public Foo<T> DoBar<T>() where T : FooBase;
Ответ 5
Будут ли использоваться методы расширения класса?
Вы можете существенно добавлять методы к классам, которые хотите, а затем вы можете называть их одинаково.
namespace ExtensionMethods
{
public static class MyExtensions
{
public static int GetName(this String str)
{
...
}
}
}
называется:
myString.GetName();
Ответ 6
С# не поддерживает такую диспетчеризацию.
и это неправильный способ для перегрузки методов также (Error'TestClass уже определяет член, называемый "GetName" с теми же типами параметров), если все внутри < > не является частью сигнатуры метода.
Ответ 7
Если вам нужно выполнять работу по типу в вашем классе, то ваш класс не является общим. Вероятно, вы должны сделать отдельный класс для каждого типа, который вы хотите обработать. Если есть какая-то функциональность, которая имеет правильную причину для генерации, вы можете поместить ее в общий базовый класс.
Пример:
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
}
Ответ 8
Как упоминалось в BFree, вы можете сделать это с деревом if или, скорее, с оператором switch, но в какой-то момент вы захотите, чтобы вы могли просто писать методы и позволить .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, чтобы сделать этот оператор switch для вас.