6

我正在努力将我们的项目从 .Net 2 升级到 .Net4.5,同时我将尽可能多地推送到 NuGet 并确保版本是最新的。

我在运行其中一项测试时遇到问题

测试类:

        public class Person
    {
        public static int PersonBaseMethodHitCount { get; set; }
        public virtual void BaseMethod()
        {
            PersonBaseMethodHitCount = PersonBaseMethodHitCount + 1;
        }
        public static int PersonSomeMethodToBeOverriddenHitCount { get; set; }
        public virtual void SomeMethodToBeOverridden()
        {
            PersonSomeMethodToBeOverriddenHitCount = PersonSomeMethodToBeOverriddenHitCount + 1;
        }
    }

    public class Employee : Person
    {
        public static int EmployeeSomeMethodToBeOverriddenHitCount { get; set; }
        public override void SomeMethodToBeOverridden()
        {
            EmployeeSomeMethodToBeOverriddenHitCount = EmployeeSomeMethodToBeOverriddenHitCount + 1;
        }
        public static int EmployeeCannotInterceptHitCount { get; set; }
        public void CannotIntercept()
        {
            EmployeeCannotInterceptHitCount = EmployeeCannotInterceptHitCount + 1;
        }

        public virtual void MethodWithParameter(
            [SuppressMessage("a", "b"), InheritedAttribute, Noninherited]string foo)
        {
        }
    }

    public class MyInterceptor : IInterceptor
    {
        public static int HitCount { get; set; }
        public void Intercept(IInvocation invocation)
        {
            HitCount = HitCount + 1;
            invocation.Proceed();
        }
    }

测试(此夹具没有设置):

var container = new WindsorContainer();
        container.Register(Component.For<MyInterceptor>().ImplementedBy<MyInterceptor>());
        container.Register(
            Component
            .For<Employee>()
            .ImplementedBy<Employee>()
            .Interceptors(InterceptorReference.ForType<MyInterceptor>())
            .SelectedWith(new DerivedClassMethodsInterceptorSelector()).Anywhere);
        container.Register(Classes.FromAssembly(Assembly.GetExecutingAssembly()).Pick().WithService.FirstInterface());

        var employee = container.Resolve<Employee>();
        Person.PersonBaseMethodHitCount = 0;
        Person.PersonSomeMethodToBeOverriddenHitCount = 0;
        Employee.EmployeeCannotInterceptHitCount = 0;
        Employee.EmployeeSomeMethodToBeOverriddenHitCount = 0;
        MyInterceptor.HitCount = 0;
        employee.BaseMethod();
        Assert.That(Person.PersonBaseMethodHitCount, Is.EqualTo(1));
        // The BaseMethod was not overridden in the derived class so the interceptor should not have been called.
        Assert.That(MyInterceptor.HitCount, Is.EqualTo(0));

        Person.PersonBaseMethodHitCount = 0;
        Person.PersonSomeMethodToBeOverriddenHitCount = 0;
        Employee.EmployeeCannotInterceptHitCount = 0;
        Employee.EmployeeSomeMethodToBeOverriddenHitCount = 0;
        MyInterceptor.HitCount = 0;
        employee.SomeMethodToBeOverridden();
        Assert.That(Person.PersonSomeMethodToBeOverriddenHitCount, Is.EqualTo(0));
        Assert.That(Employee.EmployeeSomeMethodToBeOverriddenHitCount, Is.EqualTo(1));
        Assert.That(MyInterceptor.HitCount, Is.EqualTo(1)); //The test errors out on this line

        Person.PersonBaseMethodHitCount = 0;
        Person.PersonSomeMethodToBeOverriddenHitCount = 0;
        Employee.EmployeeCannotInterceptHitCount = 0;
        Employee.EmployeeSomeMethodToBeOverriddenHitCount = 0;
        MyInterceptor.HitCount = 0;
        employee.CannotIntercept();
        Assert.That(Employee.EmployeeCannotInterceptHitCount, Is.EqualTo(1));
        Assert.That(MyInterceptor.HitCount, Is.EqualTo(0));

我添加了一条注释来说明测试失败的地方。

据我所知,问题出在 DerivedClassMethodsInterceptorSelector

选择器:

public class DerivedClassMethodsInterceptorSelector : IInterceptorSelector
{
    public IInterceptor[] SelectInterceptors(Type type, MethodInfo method, IInterceptor[] interceptors)
    {
        return method.DeclaringType != type ? new IInterceptor[0] : interceptors;
    }
}

当它进行类型比较时,类型变量是 System.RuntimeType 但应该是 Employee (至少这是我的理解)。

编辑: 这个问题是使用 Castle.Windsor 和 Castle.Core 3.2.1 发生的,在 NuGet 安装 3.1.0 包后,代码按预期工作。

我倾向于这是一个错误,但我也可能只是逻辑上的改变。

4

1 回答 1

1

通过这个简单的单元测试,我能够重现版本 3.3.3 的相同问题:

[TestClass]
public class MyUnitTest
{
    [TestMethod]
    public void BasicCase()
    {

        var ProxyFactory = new ProxyGenerator();
        var aopFilters = new IInterceptor[] {new TracingInterceptor()};
        var ConcreteType = typeof(MyChild);

        var options = new ProxyGenerationOptions { Selector = new AopSelector() };

        var proxy = ProxyFactory.CreateClassProxy(ConcreteType, options, aopFilters) as MyChild;
        proxy.DoIt();

    }
}

public class AopSelector : IInterceptorSelector
{
    public IInterceptor[] SelectInterceptors(Type runtimeType, MethodInfo method, IInterceptor[] interceptors)
    {
        Assert.IsTrue(runtimeType == typeof(MyChild));

        return interceptors;
    }
}

public class MyWay
{
    public virtual void DoIt()
    {
        Thread.Sleep(200);
    }
}
public class MyChild : MyWay
{
    public virtual void DoIt2()
    {
        Thread.Sleep(200);
    }
}

public class TracingInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        var isProperty = invocation.Method.Name.StartsWith("get_")
                      || invocation.Method.Name.StartsWith("set_");

        if (isProperty)
        {
            invocation.Proceed();
            return;
        }

        LogMethod(invocation);
    }

    protected virtual void LogMethod(IInvocation invocation)
    {
        var target = (invocation.InvocationTarget ?? invocation.Proxy).GetType().Name;
        var stopwatch = Stopwatch.StartNew();

        try
        {
            stopwatch.Start();
            invocation.Proceed();
        }
        finally
        {
            stopwatch.Stop();
            var result = stopwatch.ElapsedMilliseconds;
        }
    }
}

我通过更改 Castle 的源代码和编辑方法TypeUtil.GetTypeOrNull来修复它,如下所示:

public static Type GetTypeOrNull(object target)
{
    if (target == null)
    {
        return null;
    }

    var type = target as Type;
    if (type != null)
    {
        return type;
    }

    return target.GetType();
}

当然这是一个幼稚的修复,因为问题出在其他地方,而不是传递给此方法的对象实例,而是传递了它Type。但是检查传递的参数是否为类型Type,如果是则返回它而不是调用GetType让它工作。

于 2015-01-06T10:23:02.000 回答