如何使用DynamicProxy合并具有多个类的多个接口?

发布于 2024-10-03 12:11:26 字数 2221 浏览 0 评论 0原文

假设我们有一个从 ICatBase 和 ICatExtension 派生的接口 ICat,如下所示。对于这两个不同的接口,都有可用的实现:CatBase 和 CatExtension。如何使用 Castle 的 DynamicProxy 将它们合并到 Icat 的实例中?

是否可以创建一个代理,其中 ICatExtension 由 CatExtension 实现,而 ICatBase 由拦截器“实现”?如何才能实现这一目标?

public interface ICatBase
{
   string Name { get; set; }
   int Age { get; set; }
}

public interface ICatExtension
{
   string Description { get; }
}

public interface ICat : ICatBase, ICatExtension
{
}

public class CatBase : ICatBase
{
   public string Name { get; set; }
   public int Age { get; set; }
}

public class CatExtension : ICatExtension
{
   public string Description
   {
      get { return "Furry"; }
   }
}

编辑

我一直在尝试使用 mixin 来完成这项工作,但下面的代码会导致 NotImplementedException。

var generator = new ProxyGenerator();
var options = new ProxyGenerationOptions();
options.AddMixinInstance(new CatBase());
options.AddMixinInstance(new CatExtension());
var cat  = generator.CreateInterfaceProxyWithoutTarget<ICat>(options);        
cat.Name = "Joey";

这是一个 DynamicProxy2 错误:没有为没有目标的方法“Void set_Name(System.String)”指定拦截器。当调用没有目标的方法时,没有“继续”的实现,拦截器有责任模仿实现(设置返回值、输出参数等),

我可以创建一个自定义拦截器来拦截调用并分派到正确的接口,但我觉得一定有一个更简单/更好的方法。我说得对吗?

编辑 #2

谢谢你,克日什托夫!使用下面的行是解决方案。

var generator = new ProxyGenerator();
var options = new ProxyGenerationOptions();
options.AddMixinInstance(new CatBase());
options.AddMixinInstance(new CatExtension());

var cat = (ICat)generator.CreateClassProxyWithTarget(typeof(object), new[] { typeof(ICat)}, new object(), options);

编辑 #3

作为最后一步,我配置了一个 Windsor 容器来根据此示例创建代理。我能够做到这一点的唯一方法是指定名称“Cat”,然后通过指定名称并转换为 ICat 接口来解析 System.Object 的实例。

WindsorContainer container = new WindsorContainer();
container.Register(
    Castle.MicroKernel.Registration.Component.For<object>().
        Named("Cat").
        Proxy.AdditionalInterfaces(typeof (ICat)).
        Proxy.MixIns(new CatBase()).
        Proxy.MixIns(new CatExtension())
    );

var cat = (ICat)container.Resolve(typeof(object), "Cat");

有没有一种更优雅的方法,我可以只向容器询问 Icat 实例,而无需引用特定名称?

Suppose we have an interface ICat that is derived from ICatBase and ICatExtension as shown below. For both distinct interfaces, an implementation is available, CatBase and CatExtension. How can Castle's DynamicProxy be used to merge these into an instance of ICat?

Is it possible to create a proxy in which ICatExtension is implemented by CatExtension and ICatBase is 'implemented' by an interceptor? How can this be achieved?

public interface ICatBase
{
   string Name { get; set; }
   int Age { get; set; }
}

public interface ICatExtension
{
   string Description { get; }
}

public interface ICat : ICatBase, ICatExtension
{
}

public class CatBase : ICatBase
{
   public string Name { get; set; }
   public int Age { get; set; }
}

public class CatExtension : ICatExtension
{
   public string Description
   {
      get { return "Furry"; }
   }
}

EDIT

I have been trying to use mixins to make this work, but the code below results in a NotImplementedException.

var generator = new ProxyGenerator();
var options = new ProxyGenerationOptions();
options.AddMixinInstance(new CatBase());
options.AddMixinInstance(new CatExtension());
var cat  = generator.CreateInterfaceProxyWithoutTarget<ICat>(options);        
cat.Name = "Joey";

This is a DynamicProxy2 error: There are no interceptors specified for method 'Void set_Name(System.String)' which has no target. When calling method without target there is no implementation to 'proceed' to and it is the responsibility of the interceptor to mimic the implementation (set return value, out arguments etc)

I could create a custom interceptor that intercepts calls and dispatches to the correct interface, but I feel there must be an easier/better way. Am I correct?

EDIT #2

Thank you, Krzysztof! Using the lines below was the solution.

var generator = new ProxyGenerator();
var options = new ProxyGenerationOptions();
options.AddMixinInstance(new CatBase());
options.AddMixinInstance(new CatExtension());

var cat = (ICat)generator.CreateClassProxyWithTarget(typeof(object), new[] { typeof(ICat)}, new object(), options);

EDIT #3

As a final step, I have configured a Windsor container to create the proxy from this example. The only way I was able to do this, was by specifying a name "Cat" and resolving an instance of System.Object by specifying the name and casting to the ICat interface afterwards.

WindsorContainer container = new WindsorContainer();
container.Register(
    Castle.MicroKernel.Registration.Component.For<object>().
        Named("Cat").
        Proxy.AdditionalInterfaces(typeof (ICat)).
        Proxy.MixIns(new CatBase()).
        Proxy.MixIns(new CatExtension())
    );

var cat = (ICat)container.Resolve(typeof(object), "Cat");

Is there a more elegant way to this in which I can just ask the container for an ICat instance, without referring to a particular name?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你如我软肋 2024-10-10 12:11:26

Mixin 是您通常使用的方法。

Mixins are what you'd normally use for that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文