Domanda

Di seguito è riportato un esempio di codice e la domanda, si prega di notare che non posso usare C# 4.0 e la parola chiave dinamica.

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

Ho anche provato altri metodi usando delegate.createdelegate ma senza fortuna. È possibile?

EDIT: non ho paura di usare un metodo dinamico (e assemblatore MSIL) ma la mia conoscenza in quest'area è molto limitata.

EDIT2: ecco un esempio più vicino a quello che sto davvero cercando di fare:

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


    }

}
È stato utile?

Soluzione

Aggiornamento 3: Ok, dal momento che stai bene con una brutta soluzione, potresti voler controllare il non documentato __refvalue e __makeref Parole chiave.


Sembra che il tuo problema sia che tu voglia essere in grado di specificare il tipo per a ref object parametro da essere convertito o cambiato a.

Il problema è che non puoi semplicemente assegnare arbitrariamente una variabile di qualsiasi tipo T a a string, Per esempio. Quindi dovresti passare in un ref object o ref string per questo funzionare affatto.

Mi sembra come Oberfreak Inchiodato quello che stavi cercando di ottenere (inizialmente non sono riuscito a notare che avevi inizializzato o come un string e così chiaramente voleva il suo effettivo tipo per influenzare il comportamento del Test2 funzione). La sua risposta ha l'approccio giusto per te.

Aggiornare: Dici in un commento che ciò che stai cercando di fare è avere un comportamento dinamico che potrebbe essere raggiunto usando un dizionario. Immagino che assomigli a questo?

Aggiornamento 2: aggiornato questo Esempio basato su tuo Esempio aggiornato.

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

Quella dovrebbe funzionare. Ma non puoi davvero ottenere la stessa cosa con i generici perché non c'è modo di farlo (come sai):

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

Se ci erano, allora saresti pronto. Ma l'unico modo possibile che puoi farlo è usando la riflessione, che è brutta e costosa per qualcosa del genere e sconfiggerebbe chiaramente la tua intenzione di mantenere questo semplice e garantire buone prestazioni.

Altri suggerimenti

Il tuo commento sembra già capire come farlo:

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

Questo sta davvero trasformando il tuo commento in codice. Questo in qualche modo non fa quello che vuoi?

Le domande principali, secondo me sono: cosa vuoi fare?

Se vuoi solo assegnare una stringa a un oggetto di riferimento, potresti provare questo:

I generici possono essere definiti durante il runtime, ma non è a proprio agio e deve essere fatto per riflessione ... nella mia oppinione è un "no go", ma solo un'oppinione

Prova a usare il object.GetType() Per ottenere il tipo corrente dell'oggetto.

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

The right way to implement method Test2 would be

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

Or am I missing something here?

If you can change the ref to a regular return, you can cheat massively in 4.0 via dynamic:

dynamic foo = obj;
Test(foo);

that is now:

Test<TheActualTypeOfObj>(obj);

Full example:

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

which writes "Hello world!"

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top