Esta es una pregunta derivada que está relacionada con otra que pregunté here. Lo estoy dividiendo porque es realmente una pregunta secundaria:C# 4.0: fundición dinámica a estática
Tengo dificultades para convertir un objeto del tipo dynamic
en otro tipo estático (conocido).
que tienen una secuencia de comandos IronPython que está haciendo esto:
import clr
clr.AddReference("System")
from System import *
def GetBclUri():
return Uri("http://google.com")
nota que es simplemente Newing un tipo BCL System.Uri y devolviéndolo. Así que Sé el tipo estático del objeto devuelto.
ahora sobre la tierra en C#, estoy Newing el guión alojamiento cosas y llamar a este captador para devolver el objeto Uri:
dynamic uri = scriptEngine.GetBclUri();
System.Uri u = uri as System.Uri; // casts the dynamic to static fine
Obras no hay problema. Ahora puedo usar el objeto Uri fuertemente tipado como si originalmente se hubiera instanciado estáticamente.
embargo ....
Ahora quiero definir mi propia clase C# que será renovada dinámica en la tierra al igual que hice con el Uri. Mi sencilla clase C#:
namespace Entity
{
public class TestPy // stupid simple test class of my own
{
public string DoSomething(string something)
{
return something;
}
}
}
Ahora en Python, nuevo un objeto de este tipo y devolverlo:
sys.path.append(r'C:..path here...')
clr.AddReferenceToFile("entity.dll")
import Entity.TestPy
def GetTest():
return Entity.TestPy(); // the C# class
después en C# llaman el captador:
dynamic test = scriptEngine.GetTest();
Entity.TestPy t = test as Entity.TestPy; // t==null!!!
aquí, el yeso no funciona Tenga en cuenta que la 'prueba' objeto (dinámica) es válida - Puedo llamar a la HacerAlgo() - simplemente no abandonará al tipo estático conocido
string s = test.DoSomething("asdf"); // dynamic object works fine
así que estoy perplejo. el System.Uri de tipo BCL convertirá de un tipo dinámico al estático correcto, pero mi propio tipo no lo hará. Obviamente hay algo que no estoy haciendo esto ...
-
Actualización: Me hice un montón de pruebas para asegurarse de que mis referencias de montaje están alineando correctamente. Cambié el número de ver ensamblador referenciado y luego miré en dynamic
Objetos GetType() información en C# - es el número de versión correcto, pero aún no volverá al tipo estático conocido.
Luego creé otra clase en mi aplicación de consola para verificar que obtendría el mismo resultado, que resultó positivo: puedo obtener una referencia dynamic
en C# a un tipo estático instanciado en mi secuencia de comandos de Python, pero lo hará no volver al tipo estático conocido correctamente.
-
aún más información:
Anton sugiere a continuación que el dominio de aplicación de montaje contexto de unión es la causa más probable. Después de hacer algunas pruebas, creo que es muy probable. . . ¡pero no puedo resolver cómo resolverlo!No estaba al tanto de los contextos de ensamblaje vinculante, así que gracias a Anton me he educado más sobre la resolución de ensamblaje y los errores sutiles que surgen allí.
Así que miré el proceso de resolución de ensamblaje al colocar un controlador en el evento en C# antes de iniciar el motor de script. Eso me permitió ver el motor pitón puesta en marcha y el tiempo de ejecución empezar a resolver los montajes:
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);
... y el controlador establece el pType var al tipo que Python está cargando:
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");
}
}
Entonces, aunque el tipo utilizado por python es el mismo en C#, estoy pensando (como propuso Anton) que los diferentes contextos vinculantes significan que para el tiempo de ejecución, los dos tipos (el del contexto de carga de enlace) y la 'carga desde el contexto de enlace' son diferentes, por lo que no se puede transmitir al otro.
Así que ahora que tengo controlar la Tipo (junto con su contexto vinculante) cargado por Python, he aquí y he aquí en C# que puedo enviar el objeto dinámico para este tipo estático y funciona:
dynamic test = scriptEngine.GetTest();
var pythonBoundContextObject =
Convert.ChangeType(test, pType); // pType = python bound
string wow = pythonBoundContextObject .DoSomething("success");
Pero, suspiro, esto no soluciona totalmente el problema, porque el var pythonBoundContextObject
, mientras que del tipo correcto, aún tiene la mancha del contexto de vinculación de ensamblaje equivocado. Esto significa que no puedo pasar esto a otras partes de mi código porque todavía tenemos bizzare type mismatch donde el espectro invisible del contexto vinculante me detiene.
// 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
Por lo tanto, la resolución tendrá que ser del lado de Python: hacer que el script se cargue en el contexto de encuadernado del conjunto correcto.
en Python, si hago esto:
# in my python script
AppDomain.CurrentDomain.Load(
"Entity, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null");
el tiempo de ejecución no puede resolver mi tipo:
import Entity.TestPy #fails
intenta imprimir test.GetType() – Andrey
Tener en cuenta las [AssemblyVersion] –
Parece más o menos como si tuvieras diferentes versiones de DLL de tu ensamblaje de satélite utilizado por ironpython y C#. – Lucero