Pregunta

A continuación se muestra un ejemplo de código y la pregunta, tenga en cuenta que no puedo usar C# 4.0 y la palabra clave dinámica.

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!";
        }
    }
}

También probé algunos métodos más utilizando Delegate.CreateDelegate pero sin suerte. ¿Es esto en absoluto posible?

Editar: No tengo miedo de usar un método dinámico (y ensamblador de MSIL), pero mi conocimiento en esta área es muy limitado.

Edit2: Aquí hay un ejemplo que está más cerca de lo que realmente intento hacer:

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).


    }

}
¿Fue útil?

Solución

Actualización 3: Ok, ya que estás bien con una solución fea, es posible que desee consultar el indocumentado __refvalue y __makeref Palabras clave.


Parece que su problema es que desea poder especificar el tipo para un ref object parámetro para ser convertido o cambió a.

El problema con eso es que no puede asignar arbitrariamente una variable de ningún tipo T a un string, por ejemplo. Entonces necesitarías pasar en un ref object o ref string para que eso funcione en absoluto.

Me parece como oberfreak clavado por lo que estabas tratando de lograr (originalmente no me doy cuenta de que te habían inicializado o como un string y así claramente quería su actual tipo para influir en el comportamiento del Test2 función). Su respuesta tiene el enfoque correcto para ti.

Actualizar: Usted menciona en un comentario que lo que está tratando de hacer es tener un comportamiento dinámico que se pueda lograr utilizando un diccionario. ¿Supongo que eso se parece a esto?

Actualización 2: actualizado este ejemplo basado en su ejemplo actualizado.

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);
    }
}

Que Deberia trabajar. Pero realmente no puedes lograr lo mismo con los genéricos porque no hay forma de hacer esto (como sabes):

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

Sí hay fueron, entonces estarías todo listo. Pero la única forma posible de hacerlo es mediante el uso de la reflexión, lo cual es feo y costoso para algo como esto y claramente derrotaría su intención de mantener este simple rendimiento y garantizar un buen rendimiento.

Otros consejos

Su comentario parece que ya entiendes cómo hacerlo:

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];

Eso realmente es solo convirtiendo su comentario en código. ¿Eso de alguna manera no hace lo que quieres?

Las preguntas principales, en mi opinión, son, ¿qué quieres hacer?

Si solo desea asignar una cadena a un objeto de referencia, puede probar esto:

Los genéricos se pueden definir durante el tiempo de ejecución, pero no es muy cómodo y debe hacerse mediante la reflexión ... en mi optimismo es un "sin ir", sino solo una oppinión

Intenta usar el object.GetType() Para obtener el tipo actual del objeto.

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!";
        }
    }
}

La forma correcta de implementar el método test2 sería

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

¿O me estoy perdiendo algo aquí?

Si puedes cambiar el ref Para un regreso regular, puede hacer trampa masivamente en 4.0 a través de dynamic:

dynamic foo = obj;
Test(foo);

Eso es ahora:

Test<TheActualTypeOfObj>(obj);

Ejemplo completo:

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;
}

Lo que escribe "¡Hola mundo!"

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top