c# - CaSTLe 接口(interface)的动态代理而不是派生类

标签 c# proxy castle-windsor castle-dynamicproxy

namespace DynamicInterception
{
    public class Calculator
    {
        public virtual int Div(int a, int b)
        {
            try
            {
                return a / b;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
                return 0;
            }
        }
    }

    [Serializable]
    public abstract class Interceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            ExecuteBefore(invocation);
            invocation.Proceed();
            ExecuteAfter(invocation);
        }
        protected abstract void ExecuteAfter(IInvocation invocation);
        protected abstract void ExecuteBefore(IInvocation invocation);
    }

    public class CalculatorInterceptor : Interceptor
    {
        protected override void ExecuteBefore(Castle.DynamicProxy.IInvocation invocation)
        {
            Console.WriteLine("Start: {0}", invocation.Method.Name);
        }

        protected override void ExecuteAfter(Castle.DynamicProxy.IInvocation invocation)
        {
            Console.WriteLine("End: {0}", invocation.Method.Name);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ProxyGenerator generator = new ProxyGenerator();
            Calculator c = generator.CreateClassProxy<Calculator>(new CalculatorInterceptor());
            var r = c.Div(11, 0);
            Console.ReadKey();
        }
    }
}

是否可以替换public virtual int Div(int a,int b) 带接口(interface)

interface ICalculator
{
    int Div(int a, int b);
}

代理声明应该怎样?

ProxyGenerator generator = new ProxyGenerator();
Calculator c = generator.CreateClassProxy<Calculator>(new CalculatorInterceptor());

最佳答案

如果你想给Calculator添加一个接口(interface)并执行这两行 它的工作原理是一样的:

public interface ICalculator
{
    int Div(int a, int b);
}

public class Calculator : ICalculator
{

    public int Div(int a, int b)
    {
        try
        {
            return a / b;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message.ToString());
            return 0;
        }
    }
}

ProxyGenerator generator = new ProxyGenerator();
Calculator c = generator.CreateClassProxy<Calculator>(new CalculatorInterceptor());

但是您实际上并没有为此做任何事情——您仍在为具体的派生类型创建代理。我假设你想要类似 "CreateClassProxy<ICalculator>" 的东西.那行不通,因为 CreateClassProxywhere TClass : class 有一般约束.

你拥有的是各种CreateInterfaceProxt..您可以尝试的方法。但像下面这样的天真执行仍然行不通:

ICalculator c = generator.CreateInterfaceProxyWithoutTarget<ICalculator>(new CalculatorInterceptor());
c.Div(1, 2);

它将执行,调用拦截器并在运行 invocation.Proceed(); 时失败错误:

System.NotImplementedException This is a DynamicProxy2 error: The interceptor attempted to 'Proceed' for method 'Int32 Div(Int32, Int32)' 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)

因此,正如 CaSTLe 的良好指示性(严重)错误所指定的那样 - 您必须以某种方式为其实现 - 或者通过在拦截器中自己指示它 - 通过拥有 Component已注册该接口(interface)。

相反,您可以这样做:(检查代码中的注释)

ProxyGenerator generator = new ProxyGenerator();

ICalculator calculator = new Calculator();
var proxyCalculator = generator.CreateInterfaceProxyWithTarget(typeof(ICalculator),calculator, new CalculatorInterceptor());

calculator.Div(1, 2); // Will execute but will not be intercepted
((ICalculator)proxyCalculator).Div(11, 0); //Will execute and will be intercepted

但是在说完我上面所说的所有内容之后,如果所有这一切背后的目的是让拦截器拦截您的方法,那么只需将“good-old”注册到容器即可:

WindsorContainer container = new WindsorContainer();
container.Register(
    Component.For<CalculatorInterceptor>(),
    Component.For<ICalculator>()
             .ImplementedBy<Calculator>()
             .Interceptors<CalculatorInterceptor>());

var calculator = container.Resolve<ICalculator>();
calculator.Div(1, 0);

// Output:
// Start: Div
// Attempted to divide by zero
// End: Div

关于c# - CaSTLe 接口(interface)的动态代理而不是派生类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39013898/

相关文章:

c# - WCF 测试客户端服务调用失败

c# - .net core 2.2 windows服务完全启动后,如何配置托管服务启动?

php - 如何在 PHP 中使用 cURL 连接到 Tor 隐藏服务?

caSTLe-windsor - 接口(interface)和抽象实现的 CaSTLe Windsor 注册

C# 在不指定参数名称的情况下运行过程

c# - 两幅图像之间的差异

c# - 通过注册表更改 PPPoE DSL 连接的代理设置

python - 如何让 PhantomJS 通过代理列表进行连接?

caSTLe-windsor - 我可以告诉 CaSTLe Windsor 在单独的 AppDomain 中创建组件吗?

caSTLe-windsor - MassTransit 2.6.1 请求/响应模式 - 响应超时