Il s'agit d'une question secondaire liée à une autre que j'ai posée here. Je le scinde parce que c'est vraiment une sous-question:C# 4.0: transtypage dynamique en statique
J'ai du mal à lancer un objet de type dynamic
vers un autre type statique (connu).
J'ai un script IronPython qui fait ceci:
import clr
clr.AddReference("System")
from System import *
def GetBclUri():
return Uri("http://google.com")
Notez qu'il est tout simplement newing un type BCL System.Uri et en le retournant. Donc Je connais le type statique de l'objet retourné.
maintenant sur les terres C#, je suis substance d'hébergement newing le script et appeler ce getter pour renvoyer l'objet Uri:
dynamic uri = scriptEngine.GetBclUri();
System.Uri u = uri as System.Uri; // casts the dynamic to static fine
Works pas de problème. Je peux maintenant utiliser l'objet Uri fortement typé comme s'il était instancié à l'origine statiquement.
mais ....
Maintenant, je veux définir ma propre classe C# qui sera newed en terre dynamique comme je l'ai fait avec l'Uri. Ma classe simple C#:
namespace Entity
{
public class TestPy // stupid simple test class of my own
{
public string DoSomething(string something)
{
return something;
}
}
}
Maintenant en Python, nouveau un objet de ce type et le retourner:
sys.path.append(r'C:..path here...')
clr.AddReferenceToFile("entity.dll")
import Entity.TestPy
def GetTest():
return Entity.TestPy(); // the C# class
alors en C# appellent le getter:
dynamic test = scriptEngine.GetTest();
Entity.TestPy t = test as Entity.TestPy; // t==null!!!
ici, la distribution ne fonctionne pas. Notez que l'objet est valide « test » (dynamique) - Je peux appeler le DoSomething() - il ne veut pas jeter le type statique connu
string s = test.DoSomething("asdf"); // dynamic object works fine
donc je suis perplexe. le type BCL System.Uri va passer d'un type dynamique à un type statique correct, mais pas mon propre type. Il y a évidemment quelque chose que je ne reçois pas de cette ...
-
Mise à jour: Je l'ai fait un tas de tests pour vous assurer que mes refs d'assemblage sont toutes correctement la queue. J'ai changé le numéro de ver de l'assembly référencé puis j'ai regardé les objets dynamic
GetType() info dans C# - c'est le numéro de version correct, mais il ne sera toujours pas renvoyé au type statique connu. J'ai ensuite créé une autre classe dans mon application de console pour vérifier que j'obtiendrais le même résultat, ce qui s'est avéré positif: je peux obtenir une référence dynamic
en C# à un type statique instancié dans mon script Python, mais il faudra pas renvoyé correctement au type statique connu.
-
encore plus d'info:
Anton ci-dessous suggère que le contexte de liaison AppDomain assemblée est le coupable probable. Après avoir fait quelques tests, je pense que c'est très probable. . . mais je ne peux pas comprendre comment le résoudre!Je ne connaissais pas les contextes de liaison d'assemblage, donc grâce à Anton, je suis devenu plus éduqué sur la résolution de l'assemblage et les bugs subtils qui surgissent là-bas. J'ai donc regardé le processus de résolution de l'assemblage en plaçant un gestionnaire sur l'événement en C# avant de démarrer le moteur de script. Cela m'a permis de voir le moteur python démarrage et le moteur d'exécution commencent à résoudre: les ensembles
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);
... et le gestionnaire définit le var pType sur le type python chargement:
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");
}
}
Alors que le type utilisé par python est le même en C#, je pense (comme proposé par Anton) que les différents contextes de liaison signifient que pour l'exécution, les deux types (celui du 'contexte de liaison de chargement' et le 'loadfrom binding context') sont différents - vous ne pouvez donc pas passer à l'autre.
Alors maintenant que j'ai prise du type (avec son contexte de liaison) chargé par Python, voici et voici en C# Je peux jeter l'objet dynamique à ce type statique et il fonctionne:
dynamic test = scriptEngine.GetTest();
var pythonBoundContextObject =
Convert.ChangeType(test, pType); // pType = python bound
string wow = pythonBoundContextObject .DoSomething("success");
Mais, soupir, cela ne résout pas totalement le problème, car le var pythonBoundContextObject
du type correct, porte encore le mauvais goût du contexte de liaison d'assemblage. Cela signifie que je ne peux pas passer cela à d'autres parties de mon code parce que nous avons toujours ce désordre de type bizzare où le spectre invisible du contexte de liaison m'arrête froid. Donc, la résolution va devoir être du côté de Python: obtenir le script à charger dans le bon contexte de liaison d'assemblage.
en Python, si je fais ceci:
# in my python script
AppDomain.CurrentDomain.Load(
"Entity, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null");
le moteur d'exécution ne peut pas résoudre mon type:
import Entity.TestPy #fails
essayer d'imprimer test.GetType() – Andrey
attention à [AssemblyVersion] –
Cela ressemble beaucoup à si vous utilisiez des versions DLL différentes de votre assembly satellite utilisées par ironpython et C#. – Lucero