Общий статический class – выбор типа объекта во время выполнения

У меня есть объект типа X , который я могу (явно) получить во время выполнения.

var type = myObject.GetType(); 

И у меня есть общий статический class.

 public static class MyStaticClass { public static void DoStuff(T something) { // bla bla } } 

Я бы хотел:

 MyStaticClass.DoStuff(myObject); 

Но я не могу.

Фактически, существует только несколько типов, на которых MyStaticClass будет работать, и они имеют несколько интерфейсов. Один способ – написать:

 if (myObject.GetType() == typeof(X)) { MyStaticClass.DoStuff(myObject as X); } if (myObject.GetType() == typeof(Y)) { MyStaticClass.DoStuff(myObject as Y); } 

но это многословно, и писать, что повсюду действительно уродливо – я чувствую, что я не должен этого делать, но также и не должен делать этого.

Я не могу поверить, что решения нет. Или, по крайней мере, обходное решение? Или мой подход неправильный, чтобы начать с (что альтернатива, если это так)? Должен ли я создать базовый class (абстрактный?) Для X, Y, Z?

Вы можете сделать это с помощью отражения, используя Type.MakeGenericType – но тогда вам также понадобится использовать reflection для вызова метода. Хотя это немного больно.

Если вы используете C # 4, вы можете использовать динамическую типизацию и тип вывода – хотя это работает только для общих методов, а не общих типов , поэтому вам нужно будет использовать:

 public void DoStuffDynamic(dynamic item) { DoStuffHelper(item); } private static void DoStuffHelper(T item) { MyClass.DoStuff(item); } 

EDIT: для производительности вы можете избежать слишком большого фактического отражения. Вы можете выполнить reflection один раз для каждого типа элемента, создать делегат формы Action и кешировать его в словаре. Это может быть намного быстрее, чем выполнение рефлексии при каждом выполнении.

Вот короткая, но полная выборка:

 using System; using System.Collections.Generic; using System.Reflection; public static class MyStaticClass { private static readonly object mapLock = new object(); private static readonly Dictionary> typeActionMap = new Dictionary>(); private static readonly MethodInfo helperMethod = typeof(MyStaticClass).GetMethod("ActionHelper", BindingFlags.Static | BindingFlags.NonPublic); public static void DoStuffDynamic(object item) { if (item == null) { throw new ArgumentNullException("item"); } Type type = item.GetType(); Action action; lock (mapLock) { if (!typeActionMap.TryGetValue(type, out action)) { action = BuildAction(type); typeActionMap[type] = action; } } action(item); } private static Action BuildAction(Type type) { MethodInfo generic = helperMethod.MakeGenericMethod(type); Delegate d = Delegate.CreateDelegate(typeof(Action), generic); return (Action) d; } private static void ActionHelper(object item) { MyStaticClass.DoStuff((T) item); } } public static class MyStaticClass { public static void DoStuff(T something) { Console.WriteLine("DoStuff in MyStaticClass<{0}>", typeof(T)); } } public class Test { static void Main() { MyStaticClass.DoStuffDynamic("Hello"); MyStaticClass.DoStuffDynamic(10); } } 

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

«На самом деле существует всего несколько типов, на которых MyStaticClass будет работать, и они имеют несколько интерфейсов. Одним из способов решения этой проблемы является написать:

Так вы не можете написать метод DoStuff против общего interface ? Таким образом, вы программируете против известного интерфейса и не пытаетесь угадать, какой тип объекта есть. Весь подход кажется немного изворотливым. Тогда вы можете вообще удалить дженерики.

Это невозможно без отражения, параметры обобщенного типа должны быть известны во время компиляции. Даже если это возможно с reflectionм, я бы посоветовал это сделать. Вы должны изменить свой дизайн.