Frage

Unten finden Sie ein Codebeispiel und die Frage. Bitte beachten Sie, dass ich C# 4.0 und das dynamische Schlüsselwort NICHT verwenden kann.

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

Ich habe auch einige weitere Methoden mit Delegate.CreateDelegate ausprobiert, aber ohne Erfolg.Ist das überhaupt möglich?

Bearbeiten:Ich habe keine Angst vor der Verwendung einer dynamischen Methode (und eines MSIL-Assemblers), aber meine Kenntnisse in diesem Bereich sind sehr begrenzt.

Edit2:Hier ist ein Beispiel, das näher an dem liegt, was ich wirklich versuche:

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


    }

}
War es hilfreich?

Lösung

Update 3:OK, da Sie mit einer hässlichen Lösung einverstanden sind, sollten Sie es sich vielleicht ansehen die Undokumentierten __refvalue Und __makeref Schlüsselwörter.


Es scheint, dass Ihr Problem darin besteht, dass Sie den Typ für a angeben möchten ref object Parameter sein soll umgewandelt oder geändert Zu.

Das Problem dabei ist, dass man einer Variablen jeden Typs nicht einfach willkürlich zuweisen kann T zu einem string, Zum Beispiel.Sie müssten also a übergeben ref object oder ref string damit das funktioniert überhaupt.

Für mich sieht es so aus oberfreak Ich habe auf den Punkt gebracht, was Sie erreichen wollten (ursprünglich war mir nicht aufgefallen, dass Sie initialisiert hatten o Als ein string und wollte es also eindeutig tatsächlich Typ, um das Verhalten des zu beeinflussen Test2 Funktion).Seine Antwort hat den richtigen Ansatz für Sie.

Aktualisieren:Sie erwähnen in einem Kommentar, dass Sie ein dynamisches Verhalten anstreben, das mit einem Wörterbuch erreicht werden könnte.Ich vermute, das sieht ungefähr so ​​aus?

Update 2:Aktualisiert Das Beispiel basierend auf dein aktualisiertes Beispiel.

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

Das sollte arbeiten.Aber mit Generika kann man nicht wirklich das Gleiche erreichen, weil es (wie Sie wissen) keine Möglichkeit gibt, dies zu erreichen:

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

Wenn da war, dann sind Sie startklar.Aber die einzige Möglichkeit, dies zu erreichen, ist die Verwendung von Reflektion, die für so etwas hässlich und teuer ist und Ihre Absicht, dies einfach zu halten und eine gute Leistung sicherzustellen, eindeutig zunichte machen würde.

Andere Tipps

Ihr Kommentar sieht so aus, als ob Sie bereits verstehen, wie es geht:

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

Das macht wirklich nur Ihren Kommentar in Code. Tut das irgendwie nicht das, was Sie wollen?

Was möchten Sie meiner Meinung nach tun, was Sie tun möchten.

Wenn Sie einem Referenzobjekt nur eine Zeichenfolge zuweisen möchten, können Sie Folgendes versuchen:

Generika können während der Laufzeit definiert werden, aber es ist nicht sehr bequem und muss durch Reflexion erfolgen ... in meiner Gegenteil ist es ein "Nein Go", aber nur eine Gegenteil

Versuchen Sie es mit dem object.GetType() um den aktuellen Typ des Objekts zu erhalten.

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

Der richtige Weg, Methoden test2 zu implementieren, wäre

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

Oder vermisst ich hier etwas?

Wenn Sie die ändern können ref Zu einer regelmäßigen Rückkehr können Sie massiv in 4.0 über schummeln dynamic:

dynamic foo = obj;
Test(foo);

Das ist jetzt:

Test<TheActualTypeOfObj>(obj);

Vollständiges Beispiel:

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

Was schreibt "Hallo Welt!"

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top