Aop RealProxy 千年遇BUG

简介:

昨夜一名CYQ.Data 框架爱好者在测试V5Beta版本时,向我发一个问题, 说F5下正常,直接运行exe会报错,于是,一夜深究后,就有了今天的博文。

 

当你运行一段代码、一个软件,在运行时你发现:Debug下正常, Release下F5运行也正常,唯独Release编绎后单独运行异常,你会怎么想?

 

这个问题对我而言,脑海里不曾有过,于是蛋定思蛋,先百度了一下:发现网上信息并不多,偶尔几条也是VC++的,对于C#的,绝无仅无。

 

 

 

当我把代码发给一友人,让他也帮忙试下时,发现对方的win7 64位竟然运行正常,灵异性又提升了一个等级。

 

面对这神一般的灵异Bug,我费了N个小时折腾,找一个不能调试的Bug,因为F5下都是正常的,那个辛苦啊。

 

灵异现象已经说了,那灵异点是什么呢?标题已经出卖了这个问题,和Aop的RealProxy有关。

 

光说AOP,园子里懂的人不多,用的估计也不多,所以深入无谓,浅出又难,只好简单过过场。 

 

我是怎么发现问题是在Aop RealProxy?

这个使用常规方法,在代码段里插一些弹出信息,来缩小出错的代码片断,最终找到了它。

 

为了减少废话,这里直接讲述两点:

 

1:哪些代码有问题,哪里有问题?

以前我写过一篇文章:C# Aop简单扫盲及ORM实体类属性拦截示例,可以先理解下AOP,但是它是有问题的,就是今天的问题。

这里给出详细的错误代码,和注释错误点,代码通常都有点长,不容易看:

复制代码
   
     using System;
     using System.Reflection;
     using System.Runtime.Remoting.Activation;
     using System.Runtime.Remoting.Messaging;
     using System.Runtime.Remoting.Proxies;

     internal  class AopAttribute : ProxyAttribute
    {
         public  override MarshalByRefObject CreateInstance(Type serverType)
        {
            AopProxy proxy =  new AopProxy(serverType);
             return (proxy.GetTransparentProxy()  as MarshalByRefObject);
        }
    }
     internal  class AopProxy : RealProxy
    {
        
         public AopProxy(Type serverType) :  base(serverType)
        {
            
        }

         public  override IMessage Invoke(IMessage msg)
        {
            IMessage message3;
             if (msg ==  null)
            {
                 return msg;
            }
             if (msg  is IConstructionCallMessage)
            {
                IConstructionReturnMessage message =  base.InitializeServerObject((IConstructionCallMessage) msg);
                RealProxy.SetStubData( this, message.ReturnValue);
                 return message;
            }
             if (!(msg  is IMethodCallMessage))
            {
                 return msg;
            }
            IMethodCallMessage mcm = msg  as IMethodCallMessage;
             try
            {
                 object[] args = mcm.Args;
                message3 =  new ReturnMessage(mcm.MethodBase.Invoke( base.GetUnwrappedServer(), args), args, args.Length, mcm.LogicalCallContext, mcm);
            }
             catch (Exception exception)
            {
                 throw  new Exception(exception.Message);
            }
             return message3;
        }

      
    }
    [AopAttribute]
     public  class Users : ContextBoundObject
    {
         public Users()
        {

        }
         int i =  0; // 任何的成员变量,在被Aop调用的时候,都会报“未将对象引用到对象实例的错误”
         public  void Test()
        {
             try
            {
                i =  1;
            }
             catch (Exception err)
            {
                System.Windows.Forms.MessageBox.Show(err.Message);
            }
        }
复制代码

 

通常大量的代码测试及分析方法,我发现了,只要Aop对象涉及到内部成员变量,在Release编绎后运行就一定会报错。

 

2:如何解决。 

在历经各种无解后,我发现了,RealProxy还有另一种写法,而这另一种写法,竟然可以解决这个问题,代码如下:

复制代码
 
class AopAttribute : ProxyAttribute
    {

         public  override MarshalByRefObject CreateInstance(Type serverType)
        {
            AopProxy realProxy =  new AopProxy(serverType,  base.CreateInstance(serverType));
             return realProxy.GetTransparentProxy()  as MarshalByRefObject;

        }
    }
     class AopProxy : RealProxy
    {
        MethodInfo method;
        MarshalByRefObject _target =  null;
         public AopProxy(Type serverType,MarshalByRefObject target)
            :  base(serverType)
        {
            _target = target;
            method = serverType.GetMethod( " Set ", BindingFlags.NonPublic | BindingFlags.Instance);
        }
         public  override IMessage Invoke(IMessage msg)
        {
             if (msg !=  null)
            {
                 if (msg  is IConstructionCallMessage)
                {
                    IConstructionCallMessage constructCallMsg = msg  as IConstructionCallMessage;
                  
                    RealProxy defaultProxy = RemotingServices.GetRealProxy(_target);

                     // 如果不做下面这一步,_target还是一个没有直正实例化被代理对象的透明代理,
                    
// 这样的话,会导致没有直正构建对象。
                    defaultProxy.InitializeServerObject(constructCallMsg);

                     // 本类是一个RealProxy,它可通过GetTransparentProxy函数得到透明代理
                     return System.Runtime.Remoting.Services.EnterpriseServicesHelper.CreateConstructionReturnMessage(constructCallMsg, (MarshalByRefObject)GetTransparentProxy());

                }
                 else  if (msg  is IMethodCallMessage)
                {
                    IMethodCallMessage callMsg = msg  as IMethodCallMessage;
                     object[] args = callMsg.Args;

                     // System.Windows.Forms.MessageBox.Show(callMsg.MethodBase.ToString());

                     if (callMsg.MethodName.StartsWith( " set_ ") && args.Length ==  1)
                    {
                        method.Invoke(_target,  new  object[] { callMsg.MethodName.Substring( 4), args[ 0] }); // 对属性进行调用
                    }
                     return RemotingServices.ExecuteMessage(_target, callMsg);
                }
            }
             return msg;
        }
复制代码

 

 

3:Debug和Release还有F5,究竟隐藏怎样的秘密? 

我也不懂,这涉及更底层的问题,不在我深究的范围内,懂的人士可以留言给大伙解答下。

 

总结:

 

在编程的世界里,灵异总是无处不在的,但是找它灵异的原因,并且能找到一种解决这类事件的方法,是每个代码建造师必须具有能力。
至于为何会产生这样那样的灵异事件,在研究的范围内,可以追究原因,在非自身研究的领域,大伙看着办了。 

 

 

终于,在忙碌微博精灵系列软件的日子里,终于又抽空完成了一篇文章,感觉不容易啊。


相关文章
|
5月前
|
IDE Java 编译器
JAVA注解,你的代码需要的一次“心灵按摩”!
【6月更文挑战第29天】Java注解是提升代码可维护性的关键,它们是编译器和IDE理解代码意图的特殊标记,不同于仅作解释的注释。注解可用于编译时检查(如@Override、@NotNull)、自动生成代码(Lombok的@Getter、@Setter)、框架集成(Spring的@Autowired、MyBatis的@Mapper)。通过注解,代码变得更简洁、功能更强大,为项目带来效率提升。尝试使用注解,赋予代码新生命!
38 12
|
6月前
1001 害死人不偿命的(3n+1)猜想
1001 害死人不偿命的(3n+1)猜想
30 0
|
Go
腥风血雨中,这招救了我的代码!
腥风血雨中,这招救了我的代码!
54 0
|
程序员 BI C#
就因一行代码,被开除
就因一行代码,被开除
54 0
|
测试技术
害死人不偿命的(3n+1)猜想
害死人不偿命的(3n+1)猜想
|
IDE 开发工具 Python
这样的奇技淫巧,劝你不用也罢
这样的奇技淫巧,劝你不用也罢
138 0
|
测试技术
PAT 1001 害死人不偿命的(3n+1)猜想
对任何一个正整数 n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把 (3n+1) 砍掉一半。
92 0
|
Java 程序员
老爷子这代码,看跪了! (中)
老爷子这代码,看跪了! (中)
141 0
老爷子这代码,看跪了! (中)
|
Java
老爷子这代码,看跪了! (上)
老爷子这代码,看跪了! (上)
147 0
老爷子这代码,看跪了! (上)
|
安全 Java
老爷子这代码,看跪了! (下)
老爷子这代码,看跪了! (下)
130 0
老爷子这代码,看跪了! (下)

相关实验场景

更多
下一篇
无影云桌面