生活

解析.NET对象的跳应用程序域访问(下篇)

30 8月 , 2018  

 
 年少时,为何未为友好的梦想去拼搏一次也?纵使头破血流,也不悔有那么年少好狂。感慨很多,最近工作也酷多,博客也蛮少更新了,毕竟每个人且需要吗协调之生失去拼命。

   
转眼就顶了元宵节,匆匆忙忙的脚步是咱当也活着努力之刻画,新的同一年,我们应有奋力被投机发非雷同的生以及追求。生命不息,奋斗不只是。在上篇博文被最主要介绍了.NET的AppDomain的系消息,在本篇博文中将会主要说明.NET程序集、对象代理,以及对象的封送原理。

 
 最近以一个群里遇到一个人数说之话语,在此地不再赘述,大概意思就是是上下一心各种会各种懂,面试时各种装逼各种吊,本人真诚之求教了一晃他,问他是不是清楚这些事物的底色原理,是否了解了根源码,能否根据实际情况修改源码,谁知被外吐槽说装逼,说知识那么基本上不克啊还看源码和理解原理吧。但是自己单独想说,这不过您自己说好精通,难道会的框架不欠了解源码和规律也?难道会就是不过了解怎么概括的以为?难道是自我聊的章程不对?

一.程序集解析:

   
谈到程序集,就要懂得呀叫做程序集,我们看程序集的概念是呀。程序集大体分为两栽:一种植是类库(就是我们来看底.DLL文件);一种是可执行程序(就是咱们看看底.EXE文件)。程序集是一个或多个模块/资源文件之逻辑分组(一个模块成为单模块程序集或者单文件程序集;多独模块成为多模块程序集或者基本上文本程序集);程序集是用、安全性和版本控制的最小单元。程序集的要害做,请看下的图示:

生活 1

     
程序集并不一定对诺唯一的一个文件,也得以分包多独公文,在差不多单文本组成的次序集中,包含程序集清单的文书称为主模块,每个程序集还必须带有一个主模块,并且只生一个。对于程序集更是详实的介绍,在另外一样首博文被颇具介绍,在此处虽未以赘述,博文地址:http://www.cnblogs.com/pengze0902/p/6043525.html

 
 最近遇一个题目,那就算是有关Dapper.NET的片段题目,Dapper.NET的频率为何很高?该零件的运行规律是啊?说句实话,我找了要命漫长还并未意识类似的文章,不知情凡是未是自己之搜素方式不对,还欲发现类似好的稿子的情侣发给自己看看,知识在分享嘛,不要吝啬你的知,让咱共前进吧。

二.DotNet的目标代理解析:

   在这边大概介绍一下夫原理  

   1.目标代理概述:

     
本文主要是教课对象的超常应用程序域访问,前面介绍了应用程序域和程序集的系消息,在这边就要开上课如何来促成目标的过应用程序域的访问操作。对象超过应用程序域的操作需要明白代理及封送,代理提供了跟长途对象完全相同的接口,代理有着与长途对象了平等的接口及称号,对于客户端而言,代理就恍如远程对象同。但是代理并无含向客户端程序提供劳务之实际上代码,代理仅仅是将协调同某一样实际目标绑定,然后将客户端对友好之求打包为信,然后发送给实际目标。

   
 在这边首先介绍一下代理,就需知道少单名词“透明代理”和“真实代理”。有如下图所示:

生活 2   
透明代理是由于CLR创建的平栽专门对象,主要是为将艺术调用转换成信息交换。由上图可以望透明代理及忠实代理,透明代理及实在代理是各个对应的涉及。透明代理对象最终必须做一个特定的类别的实例。

   
一个程序获得透明代理的援后,这个顺序用当代理对象及使用方法调用。当次在透明代理对象上行使方式调用时,CLR将创一个新的信息对象为象征此调用,CLR会将这个消息传递给真实代理用于拍卖。

   
真实代理将发另外一长条信息,以表示调用的结果,透明代理将用第二久信息对这调用的对战进行中转,透明地用结果传送给调用方。如果真代理返回的应消息包含异常,透明代理将再也抛出这那个,并再同蹩脚将结果传为调用方。

 
 透明代理和真代理之间的信息交换是由此实际带来的Invoke方法发生。在透明代理对象上之道调用,导致从基于堆栈处理的音讯转换为根据消息处理的方法。再回响应消息之前,真实代理的Invoke实现可能用消息分发给任何数据的拍卖节点,为了传送调用到的一个其实目标,最终的处理节点归根结底都得将请消息转换为积聚栈帧。 
   

一.Dapper.NET概述:

 
项目开支时,我们还是待考虑项目之技巧架构,尤其是对准数据库底层的考虑于多。现在对此数据库的访问有ADO.NET,EF,Dapper.NET等等,不同之状态会出例外之选项,讨论的时节都见面说到“xx很牛逼,xx效率很高”等等,总的欲干一会,才好不容易我们开过会。(很多时段,在开会前路选什么技术就定矣,但是非起个见面不怕亮做事不严谨…),在选用Dapper.NET时,有人说交Dapper.NET效率高,很牛逼,也不知底好新人说了千篇一律词“为什么Dapper.NET效率高?”

   好尴尬…

   Dapper.NET是一个大概的ORM,专门起SQL查询结果被很快生成对象。Dapper.Net支持实施sql查询并将该结果映射到强类型列表或动态目标列表。Dapper.Net缓存每个查询的信息。这种全面的休养生息存有助于从约有数加倍于LINQ到SQL的询问生成对象。当前缓存由简单只ConcurrentDictionary对象处理,它们并未被扫除。

 
 Dapper.Net通过扩张方法以少只映射函数添加到IDbConnection接口,这点儿单函数还命名也ExecuteMapperQuery。第一单照结果是一个强类型列表,而第二单照结果是一个动态目标列表。ExecuteMapperCommand执行并且不回来结果集。所有三只措施还拿参数接受吗隐匿名类,其中属于性值映射到同名的SQL参数。

   Dapper.Net旨在仅处理结果集及目标映射。它不处理目标之间的涉及,它不见面自动生成任何项目的SQL查询。

   2.对象代理原理分析:

        上面根本介绍了代办的局部着力理论,下面看一下这些骨干目标。

    (1).RealProxy.GetTransparentProxy():返回 RealProxy
的时实例的晶莹代理。  

  public virtual object GetTransparentProxy()
    {
      return this._tp;
    }

     
 该措施在System.Runtime.Remoting.Proxies命名空间下,RealProxy类:提供摄的基本功能。

    (2).ProxyAttribute.CreateProxy():创建由指定的
ObjRef描述并雄居服务器上的远距离对象的远程处理代理的实例。 

[SecurityCritical]
    public virtual RealProxy CreateProxy(ObjRef objRef, Type serverType, object serverObject, Context serverContext)
    {
      RemotingProxy remotingProxy = new RemotingProxy(serverType);
      if (serverContext != null)
        RealProxy.SetStubData((RealProxy) remotingProxy, (object) serverContext.InternalContextID);
      if (objRef != null && objRef.GetServerIdentity().IsAllocated)
        remotingProxy.SetSrvInfo(objRef.GetServerIdentity(), objRef.GetDomainID());
      remotingProxy.Initialized = true;
      Type type = serverType;
      if (!type.IsContextful && !type.IsMarshalByRef && serverContext != null)
        throw new RemotingException(Environment.GetResourceString("Remoting_Activation_MBR_ProxyAttribute"));
      return (RealProxy) remotingProxy;
    }

 
 该措施以 System.Runtime.Remoting.Proxies命名空间下,ProxyAttribute类指示对象类型需要从定义代理。该措施接收5只参数,objRef:对而也那创立代理的长途对象的靶子引用;serverType:远程对象所当的服务器的类型;serverObject:服务器对象;serverContext:服务器对象所于的上下文。该方式以指定的
<see cref=”T:System.Runtime.Remoting.ObjRef”/>
中说明的长途对象的远距离处理代理的初实例。

   
(3).RemotingServices:提供多行使和公布远程对象及代理的道。此类不可知吃接续。

       GetRealProxy()方法返回指定透明代理后面的真人真事代理。

 [SecurityCritical]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    [MethodImpl(MethodImplOptions.InternalCall)]
    public static extern RealProxy GetRealProxy(object proxy);

   
 该办法接收参数,proxy:一个晶莹剔透代理。该方法返回透明代理后面的实事求是代理实例。

   
 IsTransparentProxy()方法返回一个布尔值,该值指示给定的目标是晶莹剔透代理要实际目标。

[SecuritySafeCritical]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    [MethodImpl(MethodImplOptions.InternalCall)]
    public static extern bool IsTransparentProxy(object proxy);

   
该办法接收一个参数,proxy:参数对而检查的对象的援。该法返回指定的目标是晶莹剔透代理要实际目标。

   ExecuteMessage():连接到指定的长距离对象,并对准那实践提供的 <see
cref=”T:System.Runtime.Remoting.Messaging.IMethodCallMessage”/>。

  [SecurityCritical]
    public static IMethodReturnMessage ExecuteMessage(MarshalByRefObject target, IMethodCallMessage reqMsg)
    {
      if (target == null)
        throw new ArgumentNullException("target");
      RealProxy realProxy = RemotingServices.GetRealProxy((object) target);
      if (realProxy is RemotingProxy && !realProxy.DoContextsMatch())
        throw new RemotingException(Environment.GetResourceString("Remoting_Proxy_WrongContext"));
      return (IMethodReturnMessage) new StackBuilderSink(target).SyncProcessMessage((IMessage) reqMsg);
    }

   
该办法接收两独参数,target:要调用其方式的长途对象。reqMsg:指定的长距离对象的主意的法门调用消息。该办法知识简单地啊目标对象创建一个堆积栈生成器,并且发送一个信息让这接收器。堆栈生成器接收器处理底层的库操作,并且调用实际的主意。当方法已时,堆栈生成器接收器把作为结果的堆栈帧转换为响应的音信,CLR用她看做该方式调用的结果返回。

二.Dapper.NET原理分析:

 
 通过Dapper.NET的源码我们好发现那个根本是“分部方法及分部类”,有关于“分部方法与分部类”的知可以拘留这篇博客:http://www.cnblogs.com/pengze0902/p/6369541.html。Dapper.Net也使连接已开辟并准备妥当,Dapper.NET通过对IDbConnection接口进行扩张。在Dapper.NET对数据库连接形成后,可以拓展连锁的操作,接下我们便来拘禁一下这些操作的兑现方式。

   1.Query()方法:

Query<T>(this IDbConnection cnn, string sql, object param = null, 
         IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null

 
 改方法表示执行查询,返回按T输入的多少。该办法是Query()方法的泛型方法,有7只参数,第一个参数为IDbConnection扩展类,表示对IDbConnection接口进行扩张,该办法运用了可选参数,提高法的扩展性。在Query方法的兑现着,有一个CommandDefinition类,用来代表sql操作的显要点。在此类下发出一个GetInit()方法。

   2.GetInit()方法:

   
我们还理解Dapper.NET通过Emit反射IDataReader的班排,来飞的得到同发对象。GetInit()方法是一个静态方法,该法的“Type
commandType”参数表示连接关联的Command对象,返回一个Action<IDbCommand>委托。

   我们就是实际看一下凡何等通过Emit反射IDataReader的队列排的。

if (SqlMapper.Link<Type, Action<IDbCommand>>.TryGet(commandInitCache, commandType, out action)){ return action; }

   Link<TKey,
TValue>是一个泛型分部类,这是一个微缓存,查看是否有一个Action<IDbCommand>的托。

var bindByName = GetBasicPropertySetter(commandType, "BindByName", typeof(bool));
var initialLongFetchSize = GetBasicPropertySetter(commandType, "InitialLONGFetchSize", typeof(int));

 
 以上两个操作主要取得BindByName和InitialLONGFetchSize的落基本性设置。

    if (bindByName != null || initialLongFetchSize != null)
            {
                var method = new DynamicMethod(commandType.Name + "_init", null, new Type[] { typeof(IDbCommand) });
                var il = method.GetILGenerator();
                if (bindByName != null)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Castclass, commandType);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.EmitCall(OpCodes.Callvirt, bindByName, null);
                }
                if (initialLongFetchSize != null)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Castclass, commandType);
                    il.Emit(OpCodes.Ldc_I4_M1);
                    il.EmitCall(OpCodes.Callvirt, initialLongFetchSize, null);
                }
                il.Emit(OpCodes.Ret);
                action = (Action<IDbCommand>)method.CreateDelegate(typeof(Action<IDbCommand>));
            }

 
 这等同步是拖欠操作的中心部分,利用Emit反射操作。根据达平等步获取之对应名称的骨干属性设置,采用DynamicMethod对象,定义及代表一个可编译,执行与摒弃的动态方法。丢弃的法可用于垃圾回收。调用该目标的GetILGenerator方法,返回方法的Microsoft中间语言(MSIL)生成器,默认的MSIL流大小为64字节。判断基本性能设置不呢空后,调用ILGenerator类的Emit方法,Emit()将指定的授命在指令流上,该措施接收一个IL流。EmitCall()将 call 或 callvirt 指令置于
Microsoft 中间语言 (MSIL)
流,以调用varargs 方法。我们视OpCodes类,该类描述中语言 (IL)
指令。CreateDelegate()完成动态方法并创立一个而用以实践其的寄托。

   通过上述之照操作构建好靶子后,就见面跟着执行相应之数据库操作。

 3.QueryImpl():

 private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefinition command, Type effectiveType)
        {
            object param = command.Parameters;
            var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param == null ? null : param.GetType(), null);
            var info = GetCacheInfo(identity, param, command.AddToCache);
            IDbCommand cmd = null;
            IDataReader reader = null;
            bool wasClosed = cnn.State == ConnectionState.Closed;
            try
            {
                cmd = command.SetupCommand(cnn, info.ParamReader);
                if (wasClosed) cnn.Open();
                reader = cmd.ExecuteReader(wasClosed ? CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess);
                wasClosed = false; 
                var tuple = info.Deserializer;
                int hash = GetColumnHash(reader);
                if (tuple.Func == null || tuple.Hash != hash)
                {
                    if (reader.FieldCount == 0) 
                        yield break;
                    tuple = info.Deserializer = new DeserializerState(hash, GetDeserializer(effectiveType, reader, 0, -1, false));
                    if (command.AddToCache) SetQueryCache(identity, info);
                }
                var func = tuple.Func;
                var convertToType = Nullable.GetUnderlyingType(effectiveType) ?? effectiveType;
                while (reader.Read())
                {
                    object val = func(reader);
                    if (val == null || val is T)
                    {
                        yield return (T)val;
                    }
                    else
                    {
                        yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);
                    }
                }
                while (reader.NextResult()) { }
                reader.Dispose();
                reader = null;
                command.OnCompleted();
            }
            finally
            {
                if (reader != null)
                {
                    if (!reader.IsClosed) try { cmd.Cancel(); }
                        catch { /* don't spoil the existing exception */ }
                    reader.Dispose();
                }
                if (wasClosed) cnn.Close();
                if (cmd != null) cmd.Dispose();
            }
        }

   
该方式吗施行查询操作的主导措施,通过CommandDefinition类的连带操作后,获取到对应的对象后,执行就同一步操作。该办法是IDbConnection的扩充方法,CommandDefinition表示sql的相干操作对象,Type表示传入的一个立竿见影之类别。Identity对象表示Dapper中的苏存查询的标识,该类是一个分部类,可以针对那个进展对应的扩展。GetCacheInfo()获取缓存信息。

三.DotNet的对象封送解析:

   
 上面介绍了代办,下面简单的介绍一下对象的封送,对象的封送分为两种,第一栽呢传值封送;第二种植啊污染引用封送。
  

三.Dapper.NET扩展:

 
 这无异部分是借花献佛,该有代码是对准Dapper.NET代码做同查封装,可以接近于操作其他ORM的章程,需要者可以自取,就无须到处去搜寻这些事物了。

 
 Dapper.NET扩展方法包

    Dapper包

   1.传值封送:

     
当在A应用程序域的对象传递给B应用程序域,.NET将A中目标的状态进行复制、序列化、然后在B中又创设,并由此代办对象开展走访。

生活 3

生活 4

                     (1 传值封送)                                      
                    (2 传引用封送)

四.总结:

   
这首博文是本身强项在头皮写的,因为基本无接近的章,连参考的素材都不曾,最多的虽是调用代码的demo,对于原理及底部源码解析基本没,在此间就就此这篇博文引出大神对那个完善的辨析。希望对大家发少数援助,也算是尽力了。

2.传援封送:

     
传引用封送的构造要达到图所示,当客户端在代理调用方法时,由代理将针对章程的求发送给长途对象,远程对象执行方要,最后再以结果传到给客户端,这种方式叫做传引用封送。传引用封送分为三种植不同之不二法门,分为客户端激活(Client
Activated)、服务端激活Singleton(Server Activated
Singleton)、服务端激活SingleCall(Server Activated
SingleCall)。三种方式的旅特征,服务对象创建且一直维系在宿主应用程序中。

   传引用封送的不二法门于此虽无举行详细介绍了。

四.总结:

    对象的越应用程序域方法的题目便介绍这么多,希望对大家有助。

, , , ,


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图