C#4.0:铸造动态静态 [英] C# 4.0: casting dynamic to static

查看:136
本文介绍了C#4.0:铸造动态静态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是公司与另一我问一个分支问题一>。我分裂它关闭,因为它确实是一个子问题:



我有铸造类型的对象困难动态到另一个(已知)静态类型



我有一个IronPython的脚本是这样做的:

 进口CLR 
clr.AddReference(系统)的系统导入*


DEF GetBclUri():
返回URI(http://google.com)

注意,这简直 newing起来一个BCL的System.Uri类型,其返回。因此,我知道返回对象的静态类型



现在在C#中的土地,我newing了脚本主机的东西,并呼吁此getter返回Uri对象:

 动态URI = scriptEngine.GetBclUri(); 
的System.Uri U = URI作为的System.Uri; //铸动态静态罚款

作品没有问题。我现在可以使用强类型的Uri对象,就好像它原本静态实例。



但是....



现在我想要定义将就像我与开放的动态的土地被newed了我自己的C#类。我简单的C#类:

 命名空间的实体
{
公共类TestPy //愚蠢的简单的测试类我自己的
{
公共字符串DoSomething的(字符串的东西)
{
返回的东西;
}
}
}



在Python现在,新一轮上涨这种类型的对象,并返回它:

  sys.path.append(R'C:..路径这里... ')
clr.AddReferenceToFile(entity.dll)
进口Entity.TestPy

DEF GetTest():
返回Entity.TestPy(); //将C#类



然后在C#中调用的getter:

 动态测试= scriptEngine.GetTest(); 
Entity.TestPy T = test作为Entity.TestPy; //ŧ== NULL!



在这里,演员不工作。请注意,测试对象(动态)是有效的 - 我可以调用DoSomething的() - 它只是不会转换为已知的静态类型



 字符串s = test.DoSomething(ASDF); //动态对象工作正常



所以我很困惑。首创置业类型的System.Uri会施放从动态类型正确的静态的,但我自己的类型不会。有很明显的东西我没有得到这个...



-



更新:我做了一系列测试,以确保我的组装裁判都排着队正确。我改变引用的程序集版本号码,然后看了看动态对象的GetType()在C#中的信息 - 这是正确的版本号,但它仍然不会投回已知的静态类型。



然后我创建了我的控制台应用程序,另一个类检查,看看我会得到相同的结果,这竟然肯定的:我可以得到一个在C#中的动态参考我的Python脚本实例化一个静态类型,但不会强制转换回已知的静态类型正确。



-



甚至更多的信息:



安东建议低于该AppDomain中集绑定上下文是可能的罪魁祸首。做一些测试后,我认为这很可能是。 。 。但我无法弄清楚如何解决它!我不知道的组装结合上下文所以感谢Anton我变得更加的教育上装配的分辨率和微妙的错误农作物在那里。



所以,我观看了大会决议通过启动脚本引擎之前,把处理程序的事件在C#过程。这让我看到了蟒蛇发动机启动和运行时启动,以解决组件:

 私有静态类型PTYPE = NULL; //这将是Python类型的REF 

//之前,脚本引擎起动,开始监测大会决议
AppDomain.CurrentDomain.AssemblyResolve
+ =新ResolveEventHandler(CurrentDomain_AssemblyResolve);



...和处理程序设置的变种p型以类型Python是加载

 静态无效CurrentDomain_AssemblyLoad(对象发件人,AssemblyLoadEventArgs参数)
{

如果(args.LoadedAssembly.FullName ==
实体,版本= 1.0.0.1,文化=中立,公钥=空)
{
当脚本引擎装入实体//组装,得到一个参考
//那种类型,所以我们可以用它来转换为更高版本。
//这种类型的裁判神奇与它承载(无形据我可以
//告诉)装配绑定上下文
PTYPE = args.LoadedAssembly.GetType(Entity.TestPy) ;
}
}



因此,虽然由Python中的类型是一样的在C#中,我想(与建议由安东)的不同结合上下文意味着到运行时,这两种类型的(一个在'装载绑定上下文和loadfrom结合上下文中)是不同的 - 让你不能施放到其他。



所以,现在我有型的保持(连同它的结合上下文)被Python,罗加载并在C#中我看见可以投的动态对象这种静态类型和它的作品:

 动态测试= scriptEngine.GetTest(); 
变种pythonBoundContextObject =
Convert.ChangeType(测试,PTYPE); // PTYPE =蟒蛇势必

串哇= pythonBoundContextObject .DoSomething(成功);



不过,叹了口气,这并不能完全解决问题,因为VAR pythonBoundContextObject ,而正确的类型,仍然带有错误的组件绑定上下文。这意味着,我不能把这传递给我的代码其他地方,因为我们仍然有这样的的bizzare类型不匹配其中,结合上下文的隐形幽灵阻止我感冒了。

  //类,它在构造函数中键入TestPy ... 
公共类Foo
{
TestPy TP;

公共美孚(TestPy T)
{
this.tp = T;
}
}

//不能通过pythonBoundContextObject(从上面):错误绑定上下文
美孚F =新的Foo(pythonBoundContextObject); //所有这艘小船失败



所以分辨率是要必须要对Python的一面:让脚本在正确装配绑定上下文加载。



在Python中,如果我这样做:

 #我python脚本
AppDomain.CurrentDomain.Load(
实体,版本= 1.0.0.1,文化=中立,公钥=空);



运行时解决不了我喜欢的类型:

 进口Entity.TestPy #fails 


解决方案

下面是从IronPython的团队,涵盖了同样的问题的答案:



http://stackoverflow.com/questions/3009213/c-ironpython-interop-with-shared-c-class-library / 3011147#3011147



(从的 http://lists.ironpython.com/pipermail/users-ironpython.com/2010-September/013717.html


This is an offshoot question that's related to another I asked here. I'm splitting it off because it's really a sub-question:

I'm having difficulties casting an object of type dynamic to another (known) static type.

I have an ironPython script that is doing this:

import clr
clr.AddReference("System")
from System import *

def GetBclUri():
    return Uri("http://google.com")

note that it's simply newing up a BCL System.Uri type and returning it. So I know the static type of the returned object.

now over in C# land, I'm newing up the script hosting stuff and calling this getter to return the Uri object:

dynamic uri = scriptEngine.GetBclUri();
System.Uri u = uri as System.Uri; // casts the dynamic to static fine

Works no problem. I now can use the strongly typed Uri object as if it was originally instantiated statically.

however....

Now I want to define my own C# class that will be newed up in dynamic-land just like I did with the Uri. My simple C# class:

namespace Entity
{
    public class TestPy // stupid simple test class of my own
    {
        public string DoSomething(string something)
        {
            return something;
        }
    }
}

Now in Python, new up an object of this type and return it:

sys.path.append(r'C:..path here...')
clr.AddReferenceToFile("entity.dll")
import Entity.TestPy

def GetTest():
    return Entity.TestPy(); // the C# class

then in C# call the getter:

dynamic test = scriptEngine.GetTest();
Entity.TestPy t = test  as Entity.TestPy; // t==null!!!

here, the cast does not work. Note that the 'test' object (dynamic) is valid--I can call the DoSomething()--it just won't cast to the known static type

string s = test.DoSomething("asdf"); // dynamic object works fine

so I'm perplexed. the BCL type System.Uri will cast from a dynamic type to the correct static one, but my own type won't. There's obviously something I'm not getting about this...

--

Update: I did a bunch of tests to make sure my assembly refs are all lining up correctly. I changed the referenced assembly ver number then looked at the dynamic objects GetType() info in C#--it is the correct version number, but it still will not cast back to the known static type.

I then created another class in my console app to check to see I would get the same result, which turned out positive: I can get a dynamic reference in C# to a static type instantiated in my Python script, but it will not cast back to the known static type correctly.

--

even more info:

Anton suggests below that the AppDomain assembly binding context is the likely culprit. After doing some tests I think it very likely is. . . but I can't figure out how to resolve it! I was unaware of assembly binding contexts so thanks to Anton I've become more educated on assembly resolution and the subtle bugs that crop up there.

So I watched the assembly resolution process by putting a handler on the event in C# prior to starting the script engine. That allowed me to see the python engine start up and the runtime start to resolve assemblies:

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);

... and the handler sets the var pType to the Type that python is loading:

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");
    }
}

So while the type used by python is the same on in C#, I'm thinking (as proposed by Anton) that the different binding contexts mean that to the runtime, the two types (the one in the 'load binding context' and the 'loadfrom binding context) are different--so you can't cast on to the other.

So now that I have hold of the Type (along with it's binding context) loaded by Python, lo and behold in C# I can cast the dynamic object to this static type and it works:

dynamic test = scriptEngine.GetTest();
var pythonBoundContextObject = 
       Convert.ChangeType(test, pType); // pType = python bound

string wow = pythonBoundContextObject .DoSomething("success");

But, sigh, this doesn't totally fix the problem, because the var pythonBoundContextObject while of the correct type, still carries the taint of the wrong assembly binding context. This means that I can't pass this to other parts of my code because we still have this bizzare type mismatch where the invisible specter of binding context stops me cold.

// 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

So the resolution is going to have to be on the Python side: getting the script to load in the right assembly binding context.

in Python, if I do this:

# in my python script
AppDomain.CurrentDomain.Load(
    "Entity, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null");

the runtime can't resolve my type:

import Entity.TestPy #fails

解决方案

Here's an answer from the IronPython team which covers the same problem:

http://stackoverflow.com/questions/3009213/c-ironpython-interop-with-shared-c-class-library/3011147#3011147

(Lifted from http://lists.ironpython.com/pipermail/users-ironpython.com/2010-September/013717.html )

这篇关于C#4.0:铸造动态静态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆