Это - вопрос об ответвлении, это связано с другим, я спросил здесь. Я откалываю его, потому что это - действительно дополнительный вопрос:
Я испытываю затруднения при кастинге объекта типа dynamic
к другому (известному) статическому типу.
У меня есть ironPython сценарий, который делает это:
import clr
clr.AddReference("System")
from System import *
def GetBclUri():
return Uri("http://google.com")
обратите внимание, что это просто newing Система BCL. Тип uri и возврат его. Таким образом, я знаю статический тип возвращенного объекта.
теперь на земле C#, я - newing сценарий, размещающий материал и называющий этот метод считывания для возврата объекта URI:
dynamic uri = scriptEngine.GetBclUri();
System.Uri u = uri as System.Uri; // casts the dynamic to static fine
Работы без проблем. Я теперь могу использовать объект URI со строгим контролем типов, как будто он первоначально инстанцировали статически.
однако....
Теперь я хочу определить свой собственный класс C#, который будет newed на динамической земле точно так же, как я сделал с Uri. Мой простой класс C#:
namespace Entity
{
public class TestPy // stupid simple test class of my own
{
public string DoSomething(string something)
{
return something;
}
}
}
Теперь в Python, новом объект этого типа и возврата это:
sys.path.append(r'C:..path here...')
clr.AddReferenceToFile("entity.dll")
import Entity.TestPy
def GetTest():
return Entity.TestPy(); // the C# class
затем в C# называют метод считывания:
dynamic test = scriptEngine.GetTest();
Entity.TestPy t = test as Entity.TestPy; // t==null!!!
здесь, бросок не работает. Обратите внимание, что 'тестовый' (динамичный) объект доступен - я могу назвать DoSomething () - он просто не бросит к известному статическому типу
string s = test.DoSomething("asdf"); // dynamic object works fine
таким образом, я озадачен. система типов BCL. Uri бросит от динамического типа до корректного статического, но мой собственный тип не будет. Существует, очевидно, что-то, что я не получаю об этом...
--
Обновление: Я сделал набор тестов, чтобы удостовериться, что мои судьи блока все выстраиваются в линию правильно. Я изменил блок, на который ссылаются, ver, число затем смотрело на dynamic
объекты GetType () информация в C# - это - число правильной версии, но это все еще не вспомнит известный статический тип.
Я затем создал другой класс в своем консольном приложении для проверки, чтобы видеть, что я получу тот же результат, который оказался положительным: Я могу получить a dynamic
ссылка в C# к статическому типу инстанцировала в моем сценарии Python, но это не вспомнит известный статический тип правильно.
--
еще больше информации:
Anton предлагает ниже этого, контекст привязки сборки AppDomain является вероятным преступником. После выполнения некоторых тестов я думаю, что это очень вероятно... но я не могу выяснить, как разрешить его! Я не знал о контекстах привязки сборки так благодаря Anton, я стал более образованным на разрешении блока и тонких ошибках, которые неожиданно возникают там.
Таким образом, я следил за процессом разрешения блока путем помещения обработчика на событие в C# до запуска механизма выполнения сценария. Это позволило мне видеть запуск механизма Python и запуск во время выполнения для разрешения блоков:
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);
... и обработчик устанавливает var pType на Тип, который загружает Python:
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");
}
}
Таким образом, в то время как тип, используемый Python, является тем же на в C#, я думаю (как предложено Anton), что различные контексты ограничения означают, что ко времени выполнения, два типа (тот в 'контексте ограничения загрузки' и 'loadfrom ограничение контекста) отличаются - таким образом, Вы не можете набрать к другому.
Таким образом теперь, когда я имею, содержат Типа (наряду с, он ограничивает контекст), загруженный Python, о чудо в C#, я могу бросить динамический объект к этому статическому типу, и он работает:
dynamic test = scriptEngine.GetTest();
var pythonBoundContextObject =
Convert.ChangeType(test, pType); // pType = python bound
string wow = pythonBoundContextObject .DoSomething("success");
Но, вздох, это не полностью решает проблему, потому что var pythonBoundContextObject
в то время как из корректного типа, все еще несет инфекцию неправильного контекста привязки сборки. Это означает, что я не могу передать это другим частям моего кода, потому что у нас все еще есть это bizzare несоответствие типов, где невидимое привидение обязательного контекста полностью прекращает меня.
// 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
Таким образом, разрешение оказывается перед необходимостью быть на стороне Python: то, чтобы заставлять сценарий загрузиться в правильном контексте привязки сборки.
в Python, если я делаю это:
# in my python script
AppDomain.CurrentDomain.Load(
"Entity, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null");
время выполнения не может разрешить мой тип:
import Entity.TestPy #fails
Наверняка IronPython загружает ваш entity.dll
в другой контекст загрузки сборки, так что у вас загружены две его копии, и типы в них, естественно, разные. Возможно, вы сможете обойти эту проблему, подключив AppDomain.AssemblyReslove
/AppDomain.AssemblyLoad
и возвращая вашу локальную сборку (typeof (Entity.TestPy).Assembly
), когда IronPython пытается загрузить ее, но я не гарантирую, что это сработает.
С System.Uri
такого не происходит, потому что mscorlib.dll
(и, возможно, некоторые другие системные сборки) обрабатываются временем выполнения особым образом.
Обновление: IronPython FAQ утверждает, что если сборка еще не загружена clr.AddReferenceToFile
использует Assembly.LoadFile
, который загружается в контекст 'Neither'. Попробуйте обратиться к методу из Entity.TestPy
перед вызовом IronPython, чтобы загрузить сборку в контекст по умолчанию Load
.