C # 4.0: Umwandlung von dynamisch in statisch

Dies ist eine Frage des Ablegers, die sich auf eine andere bezieht, die ich gestellt habeHie. Ich teile es ab, weil es wirklich eine Unterfrage ist:

Ich habe Schwierigkeiten, ein Objekt vom Typ @ zu werfedynamic auf einen anderen (bekannten) statischen Typ.

Ich habe ein ironPython-Skript, das dies ausführt:

import clr
clr.AddReference("System")
from System import *

def GetBclUri():
    return Uri("http://google.com")

Notiz, dass es einfach istNeues BCL-System.Uri-Typ und Rückgabe. SoIch kenne den statischen Typ des zurückgegebenen Objekts.

Jetzt in C # land, stelle ich das Skript-Hosting neu auf und rufe diesen Getter auf, um das Uri-Objekt zurückzugeben:

dynamic uri = scriptEngine.GetBclUri();
System.Uri u = uri as System.Uri; // casts the dynamic to static fine

Works kein Problem. Ich kann das stark typisierte Uri-Objekt jetzt so verwenden, als wäre es ursprünglich statisch instanziiert worden.

jedoch...

Nun möchte ich meine eigene C # -Klasse definieren, die im dynamischen Land neu erstellt wird, genau wie ich es mit dem Uri getan habe. Meine einfache C # -Klasse:

namespace Entity
{
    public class TestPy // stupid simple test class of my own
    {
        public string DoSomething(string something)
        {
            return something;
        }
    }
}

Jetzt in Python ein Objekt dieses Typs neu anlegen und zurückgeben:

sys.path.append(r'C:..path here...')
clr.AddReferenceToFile("entity.dll")
import Entity.TestPy

def GetTest():
    return Entity.TestPy(); // the C# class

then in C # den Getter aufrufen:

dynamic test = scriptEngine.GetTest();
Entity.TestPy t = test  as Entity.TestPy; // t==null!!!

hier funktioniert die Besetzung nicht. Beachten Sie, dass das 'Test'-Objekt (dynamisch) gültig ist - ich kann das DoSomething () aufrufen -it wird einfach nicht in den bekannten statischen Typ umgewandelt

string s = test.DoSomething("asdf"); // dynamic object works fine

so bin ich ratlos. Der BCL-Typ System.Uri wird von einem dynamischen Typ in den richtigen statischen Typ umgewandelt, mein eigener Typ jedoch nicht. Es gibt offensichtlich etwas, was ich nicht verstehe ...

-

Update: Ich habe eine Reihe von Tests durchgeführt, um sicherzustellen, dass alle Baugruppenreferenzen korrekt ausgerichtet sind. Ich habe die referenzierte Baugruppen-Versionsnummer geändert und dann das @ angesehedynamic Objekte GetType () Informationen in C # - es ist die richtige Versionsnummer, aber es wird immer noch nicht auf den bekannten statischen Typ zurückgesetzt.

Ich habe dann eine weitere Klasse in meiner Konsolen-App erstellt, um zu überprüfen, ob ich das gleiche Ergebnis erhalte, was sich als positiv herausstellte: Ich kann ein @ erhaltedynamic Verweis in C # auf einen statischen Typ, der in meinem Python-Skript instanziiert wurde, aber nicht korrekt auf den bekannten statischen Typ zurückgesetzt wird.

-

even weitere Infos:

Anton schlägt im Folgenden vor, dass der Bindungskontext der AppDomain-Assembly der wahrscheinliche Schuldige ist. Nach einigen Tests denke ich, dass es sehr wahrscheinlich ist. . . aber ich kann nicht herausfinden, wie man es löst! Ich kannte keine Assemblerbindungskontexte, daher habe ich mich dank Anton besser mit der Auflösung von Assemblern und den subtilen Fehlern, die dort auftauchen, vertraut gemacht.

So habe ich den Prozess der Assemblyauflösung verfolgt, indem ich vor dem Starten des Skriptmoduls einen Handler für das Ereignis in C # festgelegt habe. Dadurch konnte ich sehen, wie die Python-Engine gestartet und die Laufzeit gestartet wurde, um Assemblys aufzulösen:

private static Type pType = null; // this will be the python type ref

// prior to script engine starting, start monitoring assembly resolution
AppDomain.CurrentDomain.AssemblyResolve 
            += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

... und der Handler setzt den var pTypeauf den Typ, den Python lädt:

static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{

    if (args.LoadedAssembly.FullName == 
        "Entity, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null")
    {
        // when the script engine loads the entity assembly, get a reference
        // to that type so we can use it to cast to later.
        // This Type ref magically carries with it (invisibly as far as I can 
        // tell) the assembly binding context
        pType = args.LoadedAssembly.GetType("Entity.TestPy");
    }
}

Während der von Python in C # verwendete Typ derselbe ist, denke ich (wie von Anton vorgeschlagen), dass die verschiedenen Bindungskontexte für die Laufzeit die beiden Typen bedeuten (der Typ im 'Ladebindungskontext' und Die 'loadfrom binding context' sind unterschiedlich - Sie können also nicht auf den anderen übertragen.

So jetzt, da ich den Typ (zusammen mit seinem Bindungskontext) in Python geladen habe, siehe da, in C # kann ich das dynamische Objekt in diesen statischen Typ umwandeln und es funktioniert:

dynamic test = scriptEngine.GetTest();
var pythonBoundContextObject = 
       Convert.ChangeType(test, pType); // pType = python bound

string wow = pythonBoundContextObject .DoSomething("success");

Aber, seufz, das behebt das Problem nicht ganz, weil der varpythonBoundContextObject während des richtigen Typs,still trägt den Makel des falschen Assembly-Bindungskontexts. Dies bedeutet, dass ich dies nicht an andere Teile meines Codes weitergeben kann, da wir immer noch dieses @ habebizzare type mismatch wo mich das unsichtbare Gespenst des Bindungszusammenhangs abhält.

// class that takes type TestPy in the ctor... 
public class Foo
{
    TestPy tp;

    public Foo(TestPy t)
    {
        this.tp = t;
    }
}

// can't pass the pythonBoundContextObject (from above): wrong binding context
Foo f = new Foo(pythonBoundContextObject); // all aboard the fail boat

Die Auflösung muss also auf der Python-Seite liegen: Das Skript muss im richtigen Assembly-Bindungskontext geladen werden.

in Python, wenn ich das mache:

# in my python script
AppDomain.CurrentDomain.Load(
    "Entity, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null");

Die Laufzeit kann meinen Typ nicht auflösen:

import Entity.TestPy #fails

Antworten auf die Frage(4)

Ihre Antwort auf die Frage