天天看點

Aop RealProxy 千年遇BUG

當你運作一段代碼、一個軟體,在運作時你發現:debug下正常, release下f5運作也正常,唯獨release編繹後單獨運作異常,你會怎麼想?

這個問題對我而言,腦海裡不曾有過,于是蛋定思蛋,先百度了一下:發現網上資訊并不多,偶爾幾條也是vc++的,對于c#的,絕無僅無。

Aop RealProxy 千年遇BUG

當我把代碼發給一友人,讓他也幫忙試下時,發現對方的win7 64位竟然運作正常,靈異性又提升了一個等級。

面對這神一般的靈異bug,我費了n個小時折騰,找一個不能調試的bug,因為f5下都是正常的,那個辛苦啊。

靈異現象已經說了,那靈異點是什麼呢?标題已經出賣了這個問題,和aop的realproxy有關。

光說aop,園子裡懂的人不多,用的估計也不多,是以深入無謂,淺出又難,隻好簡單過過場。 

我是怎麼發現問題是在aop realproxy?

這個使用正常方法,在代碼段裡插一些彈出資訊,來縮小出錯的代碼片斷,最終找到了它。

為了減少廢話,這裡直接講述兩點:

1:哪些代碼有問題,哪裡有問題?

這裡給出詳細的錯誤代碼,和注釋錯誤點,代碼通常都有點長,不容易看:

Aop RealProxy 千年遇BUG
Aop RealProxy 千年遇BUG

    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))

            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()

                i = 1;

            catch (exception err)

                system.windows.forms.messagebox.show(err.message);

Aop RealProxy 千年遇BUG

通常大量的代碼測試及分析方法,我發現了,隻要aop對象涉及到内部成員變量,在release編繹後運作就一定會報錯。

2:如何解決。 

在曆經各種無解後,我發現了,realproxy還有另一種寫法,而這另一種寫法,竟然可以解決這個問題,代碼如下:

Aop RealProxy 千年遇BUG
Aop RealProxy 千年遇BUG

class aopattribute : proxyattribute

            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);

            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;

Aop RealProxy 千年遇BUG

3:debug和release還有f5,究竟隐藏怎樣的秘密? 

我也不懂,這涉及更底層的問題,不在我深究的範圍内,懂的人士可以留言給大夥解答下。

總結:

在程式設計的世界裡,靈異總是無處不在的,但是找它靈異的原因,并且能找到一種解決這類事件的方法,是每個代碼建造師必須具有能力。

至于為何會産生這樣那樣的靈異事件,在研究的範圍内,可以追究原因,在非自身研究的領域,大夥看着辦了。