Общий статический класс - получение типа объекта во время выполнения - PullRequest
3 голосов
/ 30 июля 2011

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

var type = myObject.GetType();

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

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

Я бы хотел сделать следующее:

MyStaticClass<myObject.GetType()>.DoStuff(myObject);

Но я не могу.

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

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

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

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

Ответы [ 3 ]

6 голосов
/ 30 июля 2011

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

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

public void DoStuffDynamic(dynamic item)
{
    DoStuffHelper(item);
}

private static void DoStuffHelper<T>(T item)
{
    MyClass<T>.DoStuff(item);
}

РЕДАКТИРОВАТЬ: Для производительности, вы можете избежать слишком много фактического отражения. Вы можете выполнить отражение один раз для каждого типа элемента, создать делегат формы Action<object> и кэшировать его в словаре. Это может быть далеко быстрее, чем выполнение отражения при каждом выполнении.

Вот короткий, но полный пример:

using System;
using System.Collections.Generic;
using System.Reflection;

public static class MyStaticClass
{
    private static readonly object mapLock = new object();

    private static readonly Dictionary<Type, Action<object>>
        typeActionMap = new Dictionary<Type, Action<object>>();

    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<object> action;
        lock (mapLock)
        {
            if (!typeActionMap.TryGetValue(type, out action))
            {
                action = BuildAction(type);
                typeActionMap[type] = action;
            }
        }
        action(item);
    }

    private static Action<object> BuildAction(Type type)
    {
        MethodInfo generic = helperMethod.MakeGenericMethod(type);
        Delegate d = Delegate.CreateDelegate(typeof(Action<object>),
                                             generic);
        return (Action<object>) d;
    }

    private static void ActionHelper<T>(object item)
    {
        MyStaticClass<T>.DoStuff((T) item);
    }
}


public static class MyStaticClass<T>
{
    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);        
    }
}

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

1 голос
/ 30 июля 2011

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

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

0 голосов
/ 30 июля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...