Questa è una domanda di derivazione correlata a un'altra che ho chiesto a here. Lo sto suddividendo perché è in realtà una sotto-domanda:C# 4.0: trasmissione dinamica a statica
Ho difficoltà a trasmettere un oggetto di tipo dynamic
a un altro (noto) tipo statico.
devo uno script IronPython che sta facendo questo:
import clr
clr.AddReference("System")
from System import *
def GetBclUri():
return Uri("http://google.com")
nota che è semplicemente Newing un tipo BCL System.Uri e il ritorno. So Conosco il tipo statico dell'oggetto restituito.
ora più in C# paese, io sono Newing lo script di hosting roba e chiamare questa getter per restituire l'oggetto Uri:
dynamic uri = scriptEngine.GetBclUri();
System.Uri u = uri as System.Uri; // casts the dynamic to static fine
Opere nessun problema. Ora posso usare l'oggetto Uri fortemente tipizzato come se fosse stato istanziato in modo statico in modo statico.
però ....
Ora voglio definire la mia classe C# che sarà newed in dinamico paese, proprio come ho fatto con l'Uri. Il mio semplice C# classe:
namespace Entity
{
public class TestPy // stupid simple test class of my own
{
public string DoSomething(string something)
{
return something;
}
}
}
Ora in Python, nuovo un oggetto di questo tipo e restituirla:
sys.path.append(r'C:..path here...')
clr.AddReferenceToFile("entity.dll")
import Entity.TestPy
def GetTest():
return Entity.TestPy(); // the C# class
poi in C# chiamano il getter:
dynamic test = scriptEngine.GetTest();
Entity.TestPy t = test as Entity.TestPy; // t==null!!!
qui, il cast non funziona. Si noti che l'oggetto 'test' (dinamica) è valida - posso chiamare il DoSomething() - semplicemente non sarà gettato al tipo statico noto
string s = test.DoSomething("asdf"); // dynamic object works fine
quindi sono perplesso. il tipo BCL System.Uri eseguirà il cast da un tipo dinamico a quello statico corretto, ma il mio tipo non lo farà. C'è ovviamente qualcosa non sto ottenendo su questo ...
-
Aggiornamento: Ho fatto un sacco di test per assicurarsi che i miei arbitri di assemblaggio sono tutti in fila in modo corretto. Ho cambiato il numero ver dell'assembly di riferimento, quindi ho esaminato le informazioni GetType() di dynamic
oggetti in C#: è il numero di versione corretto, ma non verrà eseguito il cast del tipo statico conosciuto.
Ho quindi creato un'altra classe nella mia app per console per verificare che otterrei lo stesso risultato, che è risultato positivo: posso ottenere un riferimento dynamic
in C# a un tipo statico istanziato nel mio script Python, ma sarà non ricondurre correttamente al tipo statico conosciuto.
-
ancora più informazioni:
Anton suggerisce di seguito che il dominio di applicazione di montaggio contesto vincolante è il probabile colpevole. Dopo aver fatto alcuni test penso che sia molto probabile. . . ma non riesco a capire come risolverlo!Non ero a conoscenza dei contesti di assemblaggio, quindi grazie ad Anton sono diventato più istruito sulla risoluzione dell'assemblaggio e sugli insidiosi bug che emergono.
Così ho visto il processo di risoluzione dell'assieme inserendo un gestore sull'evento in C# prima di avviare il motore di script. Questo mi ha permesso di vedere il motore pitone avvio e il runtime iniziare a risolvere le assemblee:
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);
... e il gestore imposta la var PTYPE al tipo che Python sta caricando:
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");
}
}
Così mentre il tipo usato da python è lo stesso in C#, sto pensando (come proposto da Anton) che i diversi contesti di associazione significano che al runtime, i due tipi (quello nel "contesto di binding del carico" e il "loadfrom contesto vincolante" sono diversi, quindi non puoi trasmettere l'altro.
Quindi, ora che ho in mano il tipo (insieme con il suo legame contesto) caricato da Python, lo ed ecco in C# posso cast dell'oggetto dinamica a questo tipo statico e funziona:
dynamic test = scriptEngine.GetTest();
var pythonBoundContextObject =
Convert.ChangeType(test, pType); // pType = python bound
string wow = pythonBoundContextObject .DoSomething("success");
Ma, sospiro, questo non risolve completamente il problema, perché il var pythonBoundContextObject
mentre del tipo corretto, continua a contenere la contaminazione del contesto di binding dell'assembly errato. Ciò significa che non posso passare questo ad altre parti del mio codice perché abbiamo ancora questa discrepanza di tipo bizzarro in cui lo spettro invisibile del contesto vincolante mi blocca.
// 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
Quindi la risoluzione sta andando ad avere per essere sul lato Python: ricevendo lo script per caricare nel contesto vincolante di montaggio a destra.
in Python, se faccio questo:
# in my python script
AppDomain.CurrentDomain.Load(
"Entity, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null");
il runtime non può risolvere il mio tipo:
import Entity.TestPy #fails
tenta di stampare test.GetType() – Andrey
Prestare attenzione alla [AssemblyVersion] –
Sembra quasi che tu stia usando diverse versioni DLL dell'assembly satellite usato da ironpython e C#. – Lucero