Вопрос

Ниже приведен пример кода и вопрос, обратите внимание, что я не могу использовать C# 4.0 и динамическое ключевое слово.

static class TestClass
{
    static void Main(string[] args)
    {
        Object o = "Previous value";
        Test(ref o);
        Trace.WriteLine(o);
    }

    static public void Test<T>(ref T obj)
    {
        //  The goal is to somehow invoke Test2 with the real type of obj, i.e the type in obj.GetType() 

        //  1st try:
        Test2(ref obj); // This doesn't work because the type in Test2 will be the same as T here.

        //  2nd try:
        MethodInfo mi = typeof(TestClass).GetMethod("Test2");
        mi = mi.MakeGenericMethod(new Type[] { obj.GetType() });
        mi.Invoke(null, new Object[] { obj }); // obj is no longer by reference so we need to store the object array and copy back the result after the call

        //  3rd try, successful implementation by the smartest mind of stack overflow :)
    }

    static public void Test2<T>(ref T s)
    {
        if (typeof(T) == typeof(String))
        {
            s = (T)(Object)"Hello world!";
        }
    }
}

Я также попробовал еще несколько методов, используя Delegate.createdelegate, но без удачи. Это вообще возможно?

РЕДАКТИРОВАТЬ: Я не боюсь использовать динамический метод (и MSIL Assembler), но мои знания в этой области очень ограничены.

EDIT2: Вот пример, который ближе к тому, что я действительно пытаюсь сделать:

public static class TypeHandler<T>
{
    public delegate void ProcessDelegate(ref T value);

    public static readonly ProcessDelegate Process = Init();

    private static ProcessDelegate Init()
    {
        //  Do lot's of magic stuff and returns a suitable delegate depending on the type
        return null;
    }
}


static class TestClass
{
    static public void Main(string[] args)
    {
        Object o = "Previous value";
        Test(ref o);
        Trace.WriteLine(o);
    }

    static public void Test<T>(ref T obj)
    {
        if (obj is T)
        {
        //  Optimized, common case
            TypeHandler<T>.Process(ref obj);
            return;
        }
        Type t = obj.GetType();
        //  How to call the delegate found in TypeHandler<t>.Process ? (I can get delegate but I can't call it).


    }

}
Это было полезно?

Решение

Обновление 3: Хорошо, так как вы в порядке с уродливым решением, вы можете проверить Недокументированный __refvalue а также __makeref ключевые слова.


Кажется, ваша проблема в том, что вы хотите иметь возможность указать тип для ref object параметр быть преобразованный или же измененный к.

Проблема в том, что вы не можете просто произвольно присвоить переменную любого типа T в string, Например. Так что вам нужно пройти в ref object или же ref string Для этого вообще.

Мне кажется oberfreak прибил то, чего вы пытались достичь (я изначально не заметил, что вы инициализировались o как string и таким образом явно хотел его действительный тип, чтобы влиять на поведение Test2 функция). Его ответ имеет правильный подход для вас.

Обновлять: Вы упоминаете в комментарии, что то, что вы пытаетесь сделать, - это динамическое поведение, которое может быть достигнуто с помощью словаря. Я предполагаю, что это выглядит примерно так?

Обновление 2: Обновлено это Пример на основе ваш Обновленный пример.

public static class TypeHandler // note: get rid of generic T parameter
{
    delegate void ProcessDelegate(ref object obj); // again, not generic

    static Dictionary<Type, ProcessDelegate> processors = new Dictionary<Type, ProcessDelegate>()
    {
        { typeof(string), (ref object obj) => { obj = "Hello, world!"; } }
        // etc.
    };

    public static void Process(ref object obj)
    {
        processors[obj.GetType()].Invoke(ref obj);
    }
}

Что должно сработать. Но вы не можете добиться того же с дженериками, потому что этого невозможно сделать (как вы знаете):

//          not allowed
//               |
//          -----------
//         |           |
TypeHandler<o.GetType()>.Process(ref o);

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

Другие советы

Ваш комментарий выглядит так, как будто вы уже понимаете, как это сделать:

MethodInfo mi = typeof(TestClass).GetMethod("Test2");
mi = mi.MakeGenericMethod(new Type[] { obj.GetType() });
object[] args = new object[] { obj };
mi.Invoke(null, args);
obj = (T) args[0];

Это действительно просто превращает ваш комментарий в код. Это как -то не делает то, что вы хотите?

Основные вопросы, на мой взгляд, в том, что вы хотите сделать?

Если вы просто хотите назначить строку на справочный объект, вы можете попробовать это:

Дженерики могут быть определены во время выполнения, но это не удобно и должно быть сделано по отражению ... в моем оптине это «нет», но просто оптинион

Попробуйте использовать object.GetType() Чтобы получить текущий тип объекта.

static class TestClass {
    static void Main(string[] args) {
        Object o = "Previous value";
        Test(ref o);
        Console.WriteLine(o);
        Console.ReadLine();
    }

    static public void Test<T>(ref T obj) {
        Object o = (Object)obj;
        Test2(ref o);
        obj = (T)o;
    }

    static public void Test2(ref object s) {
        if (s.GetType().Equals(typeof(String))) {
            s = "Hello world!";
        }
    }
}

Правильным способом реализации метода тестирования2 будет

static public void Test2<T>(ref T s)
    {
        if (s is string)
        {
            s = (T)(Object)"Hello world!";
        }
}

Или я что -то здесь упускаю?

Если вы можете изменить ref до регулярного возвращения, вы можете массово обманывать 4.0 через dynamic:

dynamic foo = obj;
Test(foo);

это сейчас:

Test<TheActualTypeOfObj>(obj);

Полный пример:

static void Main(string[] args)
{
    object o = "Previous value";
    o = Test2((dynamic)o);
    Trace.WriteLine(o);
}

static public T Test2<T>(T s)
{
    if (typeof(T) == typeof(string))
    {
        s = (T)(object)"Hello world!";
    }
    return s;
}

который пишет "Привет, мир!"

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top