Attribute在.NET编程的应用(六)

Robosuite实战:通过Xbox手柄实现机械臂6-DoF精准控制的完整指南 本文详细介绍了如何通过Xbox手柄实现机械臂的6-DoF精准控制,结合Robosuite仿真环境与MuJoCo物理引擎,提供从环境配置到代码实现的完整指南。文章重点解析了手柄映射原理、核心控制代码以及数据采集优化技巧,帮助开发者高效完成机械臂控制任务。 阅读详情

Attribute在.NET编程的应用(六)


(承上节) .NET Framework拦截机制的设计中,在客户端和对象之间,存在着多种消息接收器,这些消息接收器组成一个链表,客户端的调用对象的过程以及调用返回实行拦截,你可以定制自己的消息接收器,把它们插入了到链表中,来完成你对一个调用的前处理和后处理。那么调用拦截是如何构架或者说如何实现的呢?

在.NET中有两种调用,一种是跨应用域(App Domain),一种是跨上下文环境(Context),两种调用均通过中间的代理(proxy),代理被分为两个部分:透明代理和实际代理。透明代理暴露同对象一样的公共入口点,当客户调用透明代理的时候,透明代理把堆栈中的帧转换为消息(上一节提到的实现IMessage接口的对象),消息中包含了方法名称和参数等属性集,然后把消息传递给实际代理,接下去分两种情况:在跨应用域的情况下,实际代理使用一个格式化器对消息进行序列化,然后放入远程通道中;在跨上下文环境的情况下,实际代理不必知道格式化器、通道和Context拦截器,它只需要在向前传递消息之前对调用实行拦截,然后它把消息传递给一个消息接收器(实现IMessageSink的对象),每一个接收器都知道自己的下一个接收器,当它们对消息进行处理之后(前处理),都将消息传递给下一个接收器,一直到链表的最后一个接收器,最后一个接收器被称为堆栈创建器,它把消息还原为堆栈帧,然后调用对象,当调用方法结果返回的时候,堆栈创建器把结果转换为消息,传回给调用它的消息接收器,于是消息沿着原来的链表往回传,每个链表上的消息接收器在回传消息之前都对消息进行后处理。一直到链表的第一个接收器,第一个接收器把消息传回给实际代理,实际代理把消息传递给透明代理,后者把消息放回到客户端的堆栈中。从上面的描述我们看到穿越Context的消息不需要格式化,CLR使用一个内部的通道,叫做CrossContextChannel,这个对象也是一种消息接收器。

有几种消息接收器的类型,一个调用拦截可以在服务器端进行也可以在客户端进行,服务器端接收器拦截所有对服务器上下文环境中对象的调用,同时作一些前处理和后处理。客户端的接收器拦截所有外出客户端上下文环境的调用,同时也做一些前处理和后处理。服务器负责服务器端接收器的安装,拦截对服务器端上下文环境访问的接收器称为服务器上下文环境接收器,那些拦截调用实际对象的接收器是对象接收器。通过客户安装的客户端接收器称为客户端上下文环境接受器,通过对象安装的客户端接收器则称为特使(Envoy)接收器,特使接收器仅拦截那些和它相关的对象。客户端的最后一个接收器和服务器端的第一个接收器是CrossContextChannel类型的实例。不同类型的接收器组成不同的段,每个段的端点都装上称为终结器的接收器,终结器起着把本段的消息传给下一个段的作用。在服务器上下文环境段的最后一个终结器是ServerContextTerminatorSink。如果你在终结器调用NextSink,它将返回一个null,它们的行为就像是死端头,但是在它们内部保存有下一个接收器对象的私有字段。

我们大致介绍了.NET Framework的对象调用拦截的实现机制,目的是让大家对这种机制有一个认识,现在是实现我们代码的时候了,通过代码的实现,你可以看到消息如何被处理的过程。首先是为我们的程序定义一个接收器CallTraceSink:


//TraceContext.cs

using System;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Activation;

namespace NiwalkerDemo
{
   public class CallTraceSink : IMessageSink //实现IMessageSink
   {
      private IMessageSink nextSink;  //保存下一个接收器
      
      //在构造器中初始化下一个接收器
      public CallTraceSink(IMessageSink next)
      {
         nextSink=next;
      }
      
      //必须实现的IMessageSink接口属性
      public IMessageSink NextSink
      {
         get
         {
            return nextSink;
         }
      }
      
      //实现IMessageSink的接口方法,当消息传递的时候,该方法被调用
      public IMessage SyncProcessMessage(IMessage msg)
      {
         //拦截消息,做前处理
         Preprocess(msg);
         //传递消息给下一个接收器
         IMessage retMsg=nextSink.SyncProcessMessage(msg);
         //调用返回时进行拦截,并进行后处理
         Postprocess(msg,retMsg);
         return retMsg;
      }
      
      //IMessageSink接口方法,用于异步处理,我们不实现异步处理,所以简单返回null,
      //不管是同步还是异步,这个方法都需要定义
      public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
      {
         return null;
      }
      
      //我们的前处理方法,用于检查库存,出于简化的目的,我们把检查库存和发送邮件都写在一起了,
      //在实际的实现中,可能也需要把Inventory对象绑定到一个上下文环境,
      //另外,可以将发送邮件设计为另外一个接收器,然后通过NextSink进行安装
      private void Preprocess(IMessage msg)
      {
         //检查是否是方法调用,我们只拦截Order的Submit方法。
         IMethodCallMessage call=msg as IMethodCallMessage;
         
         if(call==null)
            return;
         
         if(call.MethodName=="Submit")
         {
            string product=call.GetArg(0).ToString(); //获取Submit方法的第一个参数
            int qty=(int)call.GetArg(1); //获取Submit方法的第二个参数
            
            //调用Inventory检查库存存量
            if(new Inventory().Checkout(product,qty))
               Console.WriteLine("Order availible");
            else
            {
               Console.WriteLine("Order unvailible");
               SendEmail();
            }
          }
       }
       
       //后处理方法,用于记录订单提交信息,同样可以将记录作为一个接收器
       //我们在这里处理,仅仅是为了演示
       private void Postprocess(IMessage msg,IMessage retMsg)
       {
          IMethodCallMessage call=msg as IMethodCallMessage;
          
          if(call==null)
             return;
          Console.WriteLine("Log order information");
       }
       
       private void SendEmail()
       {
          Console.WriteLine("Send email to manager");
       }
    }  
        ...  
接下来我们定义上下文环境的属性,上下文环境属性必须根据你要创建的接收器类型来实现相应的接口,比如:如果创建的是服务器上下文环境接收器,那么必须实现IContributeServerContextSink接口。
      ...
public class CallTraceProperty : IContextProperty, IContributeObjectSink
{
   public CallTraceProperty()
   {
   }
   
   //IContributeObjectSink的接口方法,实例化消息接收器
   public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink next)
   {
      return new CallTraceSink(next);
   }
   
   //IContextProperty接口方法,如果该方法返回ture,在新的上下文环境中激活对象
   public bool IsNewContextOK(Context newCtx)
   {
      return true;
   }
   
   //IContextProperty接口方法,提供高级使用
   public void Freeze(Context newCtx)
   {
   }
   
   //IContextProperty接口属性
   public string Name
   {
      get { return "OrderTrace";}
   }
}
         ...
最后是ContextAttribute
  ...
   [AttributeUsage(AttributeTargets.Class)]
   public class CallTraceAttribute : ContextAttribute
   {
      public CallTraceAttribute():base("CallTrace")
      {
      }
      
      //重载ContextAttribute方法,创建一个上下文环境属性
      public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
      {
         ctorMsg.ContextProperties.Add(new CallTraceProperty());
      }
   }
}

为了看清楚调用Order对象的Submit方法如何被拦截,我们稍微修改一下Order类,同时把它设计为ContextBoundObject的派生类:
//Inventory.cs

//Order.cs
using System;

namespace NiwalkerDemo
{
   [CallTrace]
   public class Order : ContextBoundObject
   {
      ...
      public void Submit(string product, int quantity)
      {
         this.product=product;
         this.quantity=quantity;
      }
    ...
   }
}


客户端调用代码:
...
public class AppMain
{
   static void Main()
   {
      Order order1=new Order(100);
      order1.Submit("Item1",150);
      
      Order order2=new Order(101);
      order2.Submit("Item2",150);
   }
}
...

运行结果表明了我们对Order的Sbumit成功地进行了拦截。需要说明的是,这里的代码仅仅是作为对ContextAttribute应用的演示,它是粗线条的。在具体的实践中,大家可以设计的更精妙。

后记:本来想对Attribute进行更多的介绍,发现要讲的东西实在是太多了。请允许我在其他的专题中再来讨论它们。十分感谢大家有耐心读完这个系列。如果这里介绍的内容在你的编程生涯有所启迪的话,那么就是我的莫大荣幸了。再一次谢谢大家。
(全文完)

TypeScript的安装与使用 阅读详情

相关推荐

Python CalmAn(Calcium Imaging Analysis)神经生物学工具包安装及环境配置过程

CalmAn是一个用于大规模钙成像数据分析和行为分析的Python工具箱。CaImAn实施了大规模钙成像数据分析管道中所需的一套基本方法。针对多天的运动校正、源提取、尖峰反褶积和分量配准,实现了快速且可扩展的算法。它适用于双光子和单光子荧光显微镜数据,可以在批处理和在线模式下运行;CaImAn还包含一些分析摄像机行为的例程。

Fine的优快云博客 3558

.net高级技术——Attribute

什么是Attribute?Attribute有什么用? Attribute相当于标签,比如说我们在即将拆迁的房子上会画一个拆字,还比如说被查封的公司会有一个封条!这些都是标签。那么在C#中的标签是什么样子的呢? 常见的Attribute有:[Obsolete]、 在使用一些窗体控价的时候可以使用[ReadOnly]、[DisplayName]等等! 以后在很多框架里面还会有很多的Attri...

qq_33407246的博客 1695

Cursor+Apifox MCP Server实战:5分钟搞定API自动化测试用例生成

本文详细介绍了如何利用Cursor IDE与Apifox MCP Server,在5分钟内将API文档自动转化为高质量的自动化测试用例。通过配置MCP Server建立数据桥梁,开发者可直接用自然语言指令,让AI基于真实接口规范生成可立即执行的pytest测试代码,大幅提升接口测试效率,特别适合快节奏的SaaS项目。

ooo22的博客 534

.NET学习笔记(三)----无处不在的特性

关于特性那些事

qq_37739112的博客 878

用Multisim仿真一个9V供电的双工对讲机:从电桥原理到LM1875功放调试全记录

本文详细介绍了使用Multisim仿真9V供电的双工对讲机全过程,涵盖电桥原理、NE5532前置放大设计、LM1875功放调试及双工通信实现。通过实战案例解析,帮助读者掌握模拟电路设计与调试技巧,提升电子工程实践能力。

weixin_28678831的博客 115

高速数字信号硬件设计:灵巧手方向核心技能与实战解析

在机器人产业加速演进的今天,灵巧手等高自由度末端执行器对硬件电路设计提出了更高要求。传统硬件工程师熟悉功能、功耗与EMC,而灵巧手设计还需在极小空间内融合多路电机驱动、高速数字接口与微弱模拟信号采集。信号完整性与电源完整性成为决定系统稳定性的关键:信号上升沿决定有效带宽,阻抗匹配、回流路径和去耦策略直接影响通信质量与抗干扰能力。从阻抗计算、等长设计到FPC布线,再到电源预算与纹波抑制,这些高速数字信号设计基础原理不仅适用于服务器主板,更是灵巧手控制器开发与调试的必修课。本文面向从事机器人硬件、嵌入式系统与电

weixin_29172963的博客 238

.NET 6 中,使用 ActionFilterAttribute 实现 AOP(面向切面编程)

defaultActionFilter继承: ActionFilterAttribute 过滤器需要的方法。//在执行业务代码之前可以执行的方法// 在动作执行之前执行的代码//实现一些系统功能代码Debug.WriteLine("执行控制器代码之前Action is executing...");//在执行业务代码之后可以执行的方法// 在动作执行之后执行的代码Debug.WriteLine("执行控制器代码之后Action has executed.");//这些方法允许您在返回结果之前。

dawfwafaew的博客 915

ArcGIS+PLUS+InVEST三件套实战:从零搞定土地利用变化与碳储量预测(附完整数据包)

本文详细介绍了如何整合ArcGIS、PLUS模型和InVEST模型,构建土地利用变化与碳储量预测的完整研究流水线。通过多情景模拟和生态系统服务评估,提供从数据准备到结果验证的实战指南,助力研究者高效完成生态评估项目。

weixin_30399821的博客 544

.net基础扫盲-Attribute

在我刚接触的项目中,在实体层见得最多的就是上图中标识出的东西,主要是由它完成了ORM,具体怎么实现的还不太清楚,但肯定和它的关系有很大,所以先去了解一下它,以便之后解开实现过程的真面纱!     首先,图中标记出的是Attribute类的自定义用法。一般Attribute的是这么使用的: 第一,先自定义一个Attribute类;     这里我们自定义一个developerattribute

想到,做到,得到 933

1、微软 Intune 全面指南:配置、管理与自动化

本文全面介绍了微软 Intune 的配置、管理和自动化操作,涵盖用户与设备管理、安全策略设置、跨平台应用部署、合规性监控及报告分析等内容。通过详细的操作步骤、自动化脚本示例和流程优化建议,帮助技术人员高效掌握 Intune 在混合办公环境中的实际应用,并展望其未来发展趋势。

ii567的博客 361

Dify智能体开发:Dify文件上传

相较于聊天文本,文档文件能够承载大量的信息,例如学术报告、法律合同。受限于 LLM 自身仅能够支持文件或图片,难以获取文件内更加丰富的上下文信息,应用的使用者不得不手动复制粘贴大量信息与 LLM 对话,增加了许多不必要的使用成本。

王国平的博客 2591

.Net6中4大过滤器的使用方法及应用场景

IAuthorizationFilter授权过滤器 public class CtmAuthorizationFilterAttribute : Attribute, IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) { // context.HttpContext.User.Claims context.Http...

weixin_38819951的博客 2446

ArcGIS Pro 3.4 二次开发 - 布局

本文介绍了在ArcGIS Pro SDK 3.4和.NET 8环境下操作布局工程项的相关方法。主要内容包括:引用布局工程项和关联布局,在新视图中打开或激活已有布局视图,引用活动布局视图,导入/移除布局工程项,创建基本布局或带参考线的自定义布局,修改布局页面尺寸,以及创建圆形图形元素等操作。重点演示了如何通过CIM(Core Infrastructure Model)进行高级布局配置,并详细说明了圆形图形元素的创建过程,包括几何构建、符号设置和图形生成。所有涉及UI线程的操作都遵循ArcGIS Pro SDK

Winemonk 795

Attribute在.NET编程的应用整理(六)

(承上节) .NET Framework拦截机制的设计中,在客户端和对象之间,存在着多种消息接收器,这些消息接收器组成一个链表,客户端的调用对象的过程以及调用返回实行拦截,你可以定制自己的消息接收器,把它们插入了到链表中,来完成你对一个调用的前处理和后处理。那么调用拦截是如何构架或者说如何实现的呢?在.NET中有两种调用,一种是跨应用域(App Domain),一种是跨上下文环境(Contex

我的专栏 502

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Attribute在.net编程中的应用(六)

(承上节) .NET Framework拦截机制的设计中,在客户端和对象之间,存在着多种消息接收器,这些消息接收器组成一个链表,客户端的调用对象的过程以及调用返回实行拦截,你可以定制自己的消息接收器,把它们插入了到链表中,来完成你对一个调用的前处理和后处理。那么调用拦截是如何构架或者说如何实现的呢?在.NET中有两种调用,一种是跨应用域(App Domain),一种是跨上下文环境(Contex

动感程序 3240

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

上一篇: Attribute在.NET编程中的应用(五)
下一篇: 优快云 BLOG上第一篇
niwalker
博客等级 码龄26年 56粉丝 33原创
评论 11
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值