Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 在动态程序集中扩展私有类_.net_Reflection.emit - Fatal编程技术网

.net 在动态程序集中扩展私有类

.net 在动态程序集中扩展私有类,.net,reflection.emit,.net,Reflection.emit,我正在开发一个框架,它允许为任意对象定义我所称的表示——您可以将这种表示理解为对象的一个方面。例如:某个应用程序的对象应该由渲染引擎可视化。不是扩展对象本身的类型,而是提供一个由服务(渲染引擎)提供的表示,该服务从对象读取数据(并且可以在其他表示的上下文中将数据写入) 该框架期望通过应用程序类型实现一些接口,以便使用该功能。但是,如果应用程序没有为这些接口提供实现,框架将自动对类型进行子类化,并为这些接口添加默认实现,如下所示: 框架(托管C++): 下面是一个简单的应用程序(C#): 框架在动

我正在开发一个框架,它允许为任意对象定义我所称的表示——您可以将这种表示理解为对象的一个方面。例如:某个应用程序的对象应该由渲染引擎可视化。不是扩展对象本身的类型,而是提供一个由服务(渲染引擎)提供的表示,该服务从对象读取数据(并且可以在其他表示的上下文中将数据写入)

该框架期望通过应用程序类型实现一些接口,以便使用该功能。但是,如果应用程序没有为这些接口提供实现,框架将自动对类型进行子类化,并为这些接口添加默认实现,如下所示:

框架(托管C++):

下面是一个简单的应用程序(C#):

框架在动态程序集中通过反射创建的是:

namespace Internal
{
  class Hello : Spoc.Samples.Hello, Spoc.Claire.IEntity
  {
    public void Hello()
    {
      // call the base class constructor
    }
    public void DoSomething()
    {
      // default implementation for IEntity
    }
  }
}
此对象返回给应用程序,由于从给定类型继承,因此可以不受任何限制地使用它

那有什么问题?如果应用程序将其类型定义为“public”,则所有类型都可以正常运行。如果没有,就像在上面描述的示例中一样,我将从TypeBuilder::CreateType()方法中获得一个TypeLoadException,表示“类型Spoc.Samples.Hello的访问被拒绝”

乍一看,人们可能会说:好吧,您正在尝试将私有类扩展到其程序集之外。我的论点是:是的,我确实从一个私有类派生,但在一个动态程序集中,也就是说,用“RunAndCollect”标记,所以它永远无法保存,因此,类型只能在AppDomain的当前实例中使用,而不能在其他地方使用。实际上,我没有违反私有原则,因为新类型仍然是私有的,坦率地说,在更严格的意义上:私有到当前的AppDomain实例

我已经使用了friend assembly范例,但除了Friends确实违反了严格的面向对象设计这一事实之外,我很难将我的动态程序集指定为friend。我还找到了ReflectionPermission属性,但也停止了该属性

有人能给我一些建议吗


PS:是的,我可以用一种务实的方式说,每个试图利用框架的对象都需要公开。不幸的是,我将框架视为一种工具,它不应该限制潜在语言的可能性,也不应该限制隐含知识。

既然有人建议我这样做,我最终将我的发现作为答案

使用托管动态程序集的AppDomain实例的RefectionPermissionFlag::MemberAccess集,并为程序集提供足够的证据以使其运行完全受信任,动态程序集应该能够调用/设置受信任程序集中的私有成员/类型。但是它没有,这一点由MicroSoft明确说明-RefectionPermissionFlag::MemberAccess不适用于动态程序集


有效的方法是在程序集的AssemblyInfo.cs中设置:[assembly:InternalsVisibleTo(“”],其私有类型/方法应在动态程序集中访问。痛苦的是,对于来自第三方的程序集,您不能这样做。

我最终使用了上面提到的示例的AssemblyInfo.cs中设置的:[assembly:InternalsVisibleTo(“”)]。然而,我仍然认为它应该可以工作,而不需要在使用该框架的应用程序中放置任何助手。我知道这是深奥的,因为应用程序无论如何都需要使用框架提供的工厂模式。是的,但是对于强名称,设置属性会变得更加复杂,因为需要内部程序集的公钥。您似乎感到困惑,
internal
类型与AppDomains无关,它们不能从不同的程序集使用,这正是您在这里尝试做的。既然你似乎找到了你的解决方案,你应该在可能的时候把它作为一个答案发布出来。好吧,我不认为它是一个解决方案,而认为它是一个相互作用的循环。关于“我的obviuos困惑”,我不理解你的观点。但是,“RunAndCollect”程序集不是我所说的普通程序集-这样的程序集绑定到创建它的AppDomain实例的生命周期。因此,在这样一个程序集的上下文中使用内部类时,我没有看到违反内部可见性的情况。。。这是:我想我没有困惑。此外,我想补充一些其他的发现。如果为当前AppDomain实例设置了RefectionPermissionFlag::MemberAccess,并且假定AppDomain实例运行的是完全受信任的,则可以调用/设置受信任程序集中的私有成员/类型。它根本不适用于动态程序集-这是来自MSDN的,只是手头没有链接。您看过了吗。您可以用代理来代替。在一个类中实现了一个默认实现,然后在调用默认对象失败时将ImpromptuForwarder子类化为,然后让impromptu将接口代理发送给转发器。然后,没有什么是子类内部或私有的,只是调用,这是更容易的方式。
namespace Spoc.Samples
{
  class Hello
  {
    public Hello()
    {
      Console.WriteLine("Hello world") ;
    }

    static void Main(string[] args)
    {
      Entity.New(typeof(Hello)) ; // creates the "Hello" object within the context of the framework
    }
  }
}
namespace Internal
{
  class Hello : Spoc.Samples.Hello, Spoc.Claire.IEntity
  {
    public void Hello()
    {
      // call the base class constructor
    }
    public void DoSomething()
    {
      // default implementation for IEntity
    }
  }
}