C# 4.0: кастинг, динамичный к помехам

Это - вопрос об ответвлении, это связано с другим, я спросил здесь. Я откалываю его, потому что это - действительно дополнительный вопрос:

Я испытываю затруднения при кастинге объекта типа 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

12
задан Community 23 May 2017 в 12:08
поделиться

1 ответ

Наверняка 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.

2
ответ дан 2 December 2019 в 23:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: