C # 4.0: приведение динамического к статическому
Это ответ на вопрос, связанный с другим, который я задалВот, Я делю это, потому что это подвопрос:
У меня возникают трудности при использовании объекта типаdynamic
к другому (известному) статическому типу.
У меня есть скрипт ironPython, который делает это:
import clr
clr.AddReference("System")
from System import *
def GetBclUri():
return Uri("http://google.com")
обратите внимание, что это простообновить тип BCL System.Uri и вернуть его, ТакЯ знаю статический тип возвращенного объекта.
Теперь, в C # land, я обновляю материал для размещения скриптов и вызываю этот геттер, чтобы вернуть объект Uri:
dynamic uri = scriptEngine.GetBclUri();
System.Uri u = uri as System.Uri; // casts the dynamic to static fine
Работает без проблем. Теперь я могу использовать строго типизированный объект Uri, как если бы он изначально создавался статически.
тем не мение....
Теперь я хочу определить свой собственный класс C #, который будет обновляться в динамической стране, как я это сделал с 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!!!
здесь актерский состав не работает. Обратите внимание, что объект 'test' (динамический) действителен - я могу вызвать DoSomething () -это просто не приведёт к известному статическому типу
string s = test.DoSomething("asdf"); // dynamic object works fine
так что я озадачен. тип BCL System.Uri приведёт динамический тип к правильному статическому, а мой собственный тип - нет. Очевидно, я чего-то не понимаю ...
-
Обновление: я сделал кучу тестов, чтобы убедиться, что все ссылки на сборки выстроены правильно. Я изменил ссылочный номер версии сборки, а затем посмотрел наdynamic
Объекты GetType () info в C # - это правильный номер версии, но он все равно не будет приведен к известному статическому типу.
Затем я создал другой класс в своем консольном приложении, чтобы проверить, получу ли я тот же результат, который оказался положительным: я могу получитьdynamic
ссылка в C # на статический тип, созданный в моем скрипте Python, но он не будет корректно возвращен к известному статическому типу.
-
еще больше информации:
Ниже Антон предполагает, что вероятным виновником является контекст привязки сборки AppDomain. После некоторых тестов я думаю, что это очень вероятно. , , но я не могу понять, как решить это! Я не знал о контекстах привязки сборки, поэтому благодаря Антону я стал более образованным в отношении разрешения сборки и обнаруженных там тонких ошибок.
Поэтому я наблюдал за процессом разрешения сборки, поместив обработчик события в 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);
... и обработчик устанавливает переменную pTypeТипу, который загружает питон:
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 #, я думаю (как предложил Антон), что разные контексты привязки означают, что для среды выполнения два типа (один в «контексте привязки загрузки» и 'loadfrom привязки контекста) разные - так что вы не можете перейти на другой.
Итак, теперь, когда у меня есть тип (вместе с его связующим контекстом), загруженный Python, вот и в C # я могу привести динамический объект к этому статическому типу, и он работает:
dynamic test = scriptEngine.GetTest();
var pythonBoundContextObject =
Convert.ChangeType(test, pType); // pType = python bound
string wow = pythonBoundContextObject .DoSomething("success");
Но, вздох, это не решает проблему полностью, потому что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