【飞秋】使用C# 4编写动态的代码

c# 飞秋发送端原码 ---笔记 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; //网络通讯的技 阅读详情

(1)使用C# 4编写动态的代码

         C# 4新增了一个dynamic关键字,可以用它来编写“动态”的代码。

         例如,以下代码创建了一个ExpandoObject对象(注意必须定义为dynamic):

 

      dynamic dynamicObj = new ExpandoObject();

 

         这一对象的奇特之处在于,我们可以随时给它增加新成员:

       

    dynamicObj.Value = 100; //添加字段

    dynamicObj.Increment = new Action(() => dynamicObj.Value++); //添加方法

 

         这些动态添加的成员与普通的类成员用法一样:
即时通讯软件
 

    for (int i = 0; i < 10; i++)

        dynamicObj.Increment();//调用方法

    Console.WriteLine("dynamicObj.Value={0}",dynamicObj.Value);//访问字段

 

         ExpandoObject对象实现了IDictionary<string, object>接口,可看成是一个字典对象,所有动态添加的成员都是这个字典对象中的元素,这意味我们不仅可以添加新成员,还可以随时移除不再需要的成员:

 

    //移除Increment方法

    (dynamicObj as IDictionary<string, object>).Remove("Increment");

 

         方法移除之后,再尝试访问此方法将引发RuntimeBinderException异常。
(2)使用dynamic关键字简化与COM组件交互的代码

    要在.NET这个“托管世界”里调用“非托管世界”中的COM组件,我们必须通过 “互操作程序集(Interop Assembly)”作为桥梁,“互操作程序集”定义了CLR类型与COM类型之间的对应关系。

         只要给.NET项目添加对“互操作程序集”的引用,就可以在.NET应用程序中创建这一程序集所包容的各种类型的实例(即COM包装器对象),对这些对象的方法调用(或对其属性的存取)将会被转发给COM组件。

         以调用Word为例,在C# 4.0之前您可能经常需要编写这样的代码:

 

    Object wordapp = new Word.Application();   //创建Word对象

    Object fileName = “MyDoc.docx” ;//指定Word文档

    Object argu = System.Reflection.Missing.Value;

    Word.Document doc = wordapp.Documents.Open(ref fileName, ref argu,

                ref argu, ref argu, ref argu, ref argu, ref argu, ref argu,

                ref argu, ref argu, ref argu, ref argu, ref argu, ref argu,

                ref argu, ref argu);

 

         上述对Open()方法的调用语句只能用“恐怖”一词来形容,其原因是Word组件中的Open()方法定义了太多的参数。

         C#4使用dynamic关键字,配合从Visual Basic中学来的“命名参数与可选参数”这两个新语法特性,可以写出更简洁的代码:

 

    dynamic wordapp = new Word.Application();

    dynamic doc = wordapp.Documents.Open(FileName: “MyDoc.docx”);

 

         上述代码中省去了用不着的参数,并且可以去掉参数前的ref关键字。

         当上述代码运行时,DLR会使用反射技术将dynamic表达式“绑定(bind)”到COM互操作程序集中所包容的Word.Application代理对象。
(3)C# 4动态编程技术内幕

         C#4中所定义的dynamic变量可以引用以下类型的对象:

l 传统的“静态”的CLR对象。

l COM包装器对象。前面已经介绍了这方面的内容。

l 实现了IDynamicMetaObjectProvider接口的“动态对象”,ExpandoObject就是这种类型对象的实例。

l 基于DLR实现的动态语言(比如IronRuby和IronPython)所创建的对象。

         从C#程序员角度来看,所有这四种对象都是一样的,都可用一个dynamic变量引用之,而DLR在程序运行时动态地将方法调用和字段存取请求“绑定”到真正的对象上。

         dynamic的功能是由DLR所支撑的,是C#编译器与DLR分工合作的成果。

         请看以下示例代码:

 

    dynamic d = 100;

    d++;

 

         C#编译器在处理上述代码时,它并不去检查变量d是否可以支持自增操作,而是为其创建了一个CallSite<T>对象(<>p__Site1):

 

    private static class <Main>o__SiteContainer0 {

        public static CallSite<Func<CallSite, object, object>> <>p__Site1;

    }

 

         中文MSDN将CallSite<T>译为“动态(调用)站点”,它是DLR中的核心组件之一。

         动态站点对象通过CallSite<T>.Create()方法创建, C#编译器会为其指定一个派生自CallSiteBinder的对象(称为“动态站点绑定对象”)作为其参数。

         动态站点绑定对象是与具体语言相关的,比如IronPython和C#都有各自的动态站点绑定对象。

         动态站点绑定对象的主要工作是将代码中的动态表达式(本例中为d++)转换为一棵“抽象语法树(AST:Abstract Syntax Tree)”,这棵语法树被称为“DLR Tree”,是在.NET 3.5所引入的LINQ表达式树的基础上扩充而来的,因此,有时又称其为“表达式树(Expression Tree)”

         DLR在内部调用此表达式树的Compile()方法生成IL指令,得到一个可以被CLR所执行的委托(在本例中其类型就是Func<CallSite, object, object>)。

         动态调用站点对象(本例中为<>p__Site1)有一个Target属性,它负责引用这一生成好的委托。

         委托生成之后,动态表达式的执行就体现为委托的执行,其实参由C#编译器直接“写死”在IL代码中。

         简化的代码示意如下(通过Reflector得到,为便于阅读,修改了变量名):

 

    object d = 100;

    object CS$0$0000 = d;

    if (<>p__Site1 == null)

        <>p__Site1 = CallSite<Func<CallSite, object, object>>.Create(……);

    d = <>p__Site1.Target(<>p__Site1, CS$0$0000);

     

         上述类型推断、方法绑定及IL代码生成的工作都是在程序运行时完成的。
(4)动态代码很慢吗?

         动态编程语言易学易用,代码紧凑,开发灵活,但性能则一直是它的“软肋”。为了提升性能,DLR设计了一个三级缓存策略。

         动态站点绑定对象会为动态调用表达式转换而成的语法树加上相应的测试条件(称为“test”),构成一个“规则(Rule)”,这个规则可以用于判断某个语法树是否可用于特定的动态调用表达式。

         举个例子,请看以下这个动态表达式:

 

    d1 + d2

 

         如果在程序运行时d1和d2都是int类型的整数,则DLR生成的规则为:

     

    if( d1 is int && d2 is int) //测试条件

        return (int)d1+(int)d2; //语法树

 

         DLR通过检查规则中的“测试条件”,就可以知道某个动态表达式是否可以使用此规则所包容的语法树。

         “规则”是DLR缓存的主要对象。

         前面介绍过的动态站点对象Target属性所引用的委托是第一级缓存,它实现的处理逻辑是这样的:

 

    //当前处理规则,属于第1级缓存

    if( d1 is int && d2 is int) //测试条件

        return (int)d1+(int)d2; //满足测试条件,直接返回一个表达式树

    //未命中,则在第2级、第3级缓存中查找,如果找到了,用找到的结果更新第1级缓存

    return site.Update(site,d1,d2);

 

         如果3级缓存中都没有命中的规则,则此动态站点所关联的调用站点绑定对象会尝试创建一个新的规则。如果创建新规则失败,则由当前编程语言(比如C#)所提供的默认调用站点绑定对象决定如何处理,通常的作法是抛出一个异常。

         当前版本的DLR第2级缓存了10条规则,第3级则缓存了100条规则。

        由于DLR自身设计了一个“规则”缓存系统,又充分利用了CLR所提供的JIT缓存(因为所有动态调用代码最终都会转换为CLR可以执行的IL指令,而CLR可以缓存这些代码),使得动态代码仅仅在第一次执行时性能较差,后续的连续调用其性能可以逼近静态代码。
3 C# 4与动态语言的集成

         由于几乎所有的编程语言都可以使用抽象语法树来表达,因此,在理论上DLR支持无限多种编程语言间的互操作,在当前版本中,可以实现C#/Visual Basic与IronPython和IronRuby的互操作,相信很快会出现其他动态编程语言的DLR实现。

         一个有趣的地方是当前基于DLR实现的动态编程语言都以“Iron”开头,比如IronRuby和IronPython。IronPython的设计者、DLR的架构设计师Jim Hugunin曾经在微软PDC 2008大会上解释说主要是为了避免起一个“Python.NET”或“Python for .NET”之类“微软味十足”的名字,才有了“IronPython”。他强调:“Iron”系列动态语言将严格遵循动态语言自身的标准和规范,尊重这些动态语言已有的历史和积累,不会引入一些仅限于.NET平台的新语言特性,并且这些语言的.NET实现保持开源。与此同时,Jim Hugunin指出 “Iron”系列语言能很好地与.NET现有类库、编程语言和工具集成,并且能“嵌入”到.NET宿主程序中。
(1)动态对象通讯协议

         由于各种动态编程语言之间的特性相差极大,实现各语言间的互操作是个难题。为此DLR采取了一个聪明的策略,它不去尝试设计一个“通用的类型系统”(CLR就是这么干的),而是设计了一个“通用的对象通讯协议”,规定所有需要互操作的动态对象必须实现IDynamicMetaObjectProvider接口,此接口定义了一个GetMetaObject()方法,接收一个语法树对象作为参数,向外界返回一个“动态元数据(DynamicMetaObject)”对象:

 

        DynamicMetaObject GetMetaObject(Expression parameter);

 

   DynamicMetaObject对象向外界提供了两个重要属性:Restrictions引用一组测试条件,Expression属性则引用一个语法树。这两个属性组合起来就是可供动态站点对象缓存的“规则(Rule)”。

         DLR中的“动态站点绑定对象(CallSiteBinder)”获取了DynamicMetaObject对象之后,它调用此对象所提供的各个方法创建“规则”,让“动态站点对象(CallSite<T>)”的Target属性引用它,完成动态绑定的工作。
(2)动态语言集成环境

         为了方便地实现静态编程语言与各种动态编程语言间的相互集成,DLR提供了一整套称为“通用寄宿(Common Hosting)”的组件,其中包容ScriptRuntime、ScriptScope等类型。

         下面我们以IronPython为例,介绍如何在C# 4开发的程序中集成动态编程语言代码。

         首先需要创建一个ScriptRuntime对象,它是一个最顶层的对象,用于在一个.NET应用程序域中“嵌入”一个特定动态语言的运行环境:

 

    ScriptRuntime pythonRuntime = Python.CreateRuntime();

 

         接着需要创建一个ScriptEngine对象,它是动态语言代码的执行引擎:

 

    ScriptEngine engine = pythonRuntime.GetEngine("py");

 

         ScriptScope对象类似于C#中的命名空间,其中可以通过定义一些变量向动态代码传入数据,比如下述代码将一个C# 创建的ExpandoObject对象传给Python代码:

 

    ScriptScope scope = pythonRuntime.CreateScope();

    //C#创建动态对象

     dynamic expando = new ExpandoObject();

    expando.Name = "JinXuLiang"; //动态添加一个字段

     //让IronPython接收C#创建的Expando对象

    scope.SetVariable("ExpandoObject", expando);

    string pythonCode = "print ExpandoObject.Name";

    //IronPython引擎执行Python语句

    engine.CreateScriptSourceFromString(pythonCode).Execute(scope);          

 

         上述示例代码是直接执行Python代码。在实际开发中,更常见的是直接执行Python文件中的代码,假设有一个Calculator.py文件,其中定义了一个Add函数:

 

    def Add(a,b):

        return a+b

 

         则以下C#代码可以直接执行之:

 

    ScriptRuntime pythonRuntime = Python.CreateRuntime();

    dynamic pythonFile = pythonRuntime.UseFile("Calculator.py");

    Console.WriteLine(pythonFile.Add(100, 200));

 

         上述示例说明在DLR的支持之下,可以让静态编程语言使用动态语言所开发的库,反过来,基于DLR实现的动态编程语言也能使用为静态语言所设计的库,比如标准的.NET基类库。

         这意味着两点:

         (1)我们现在可以将“静态”和“动态”编程语言组合起来,开发出一些具有高度交互性的应用程序,使用静态编程语言搭建系统框架,使用动态编程语言实现交互性,这是一个很值得注意的应用领域。

         (2)将来会出现一些“静态”“动态”编程语言同时适用的库,向实现“无所不在的复用”目标又前进了一步。

         Visual Studio 2010为新的.NET编程语言F#提供了专门的项目模板,但没有为IronPython和IronRuby之类动态语言的开发提供支持,相信随着动态语言在.NET平台之上的应用日趋广泛,后继版本的Visual Studio会直接支持动态语言的开发。

 

 

 

关注技术文章飞秋:http://www.freeeim.com/,24小时专业转载。

使用T4模板进行C#代码生成 有过前端开发经验的同学一定了解模板文件的重要用户。其实C#也有类似的模板功能(T4模板),不仅可以生成html文件,还可以生成代码。今天就给大家介绍一下。 什么是T4模板 T4模板全称是Text Template Transformation Toolkit,因为四个单词的开头字母都是T,所以称作T4模板。 T4模板是一种支持C#或者VB代码开发的模板格式,已经在Visual Studio,Mo... 阅读详情

相关推荐

在c#编写的软件中动态地编译新的代码

 首先解释一下:这里用到了几个类,CodeDomProvider 、CompilerParameters 、CompilerResults 。CodeDomProvider类提供了我们编译代码的容器,我们通过它来工作; 大家都知道,现在我们要做的是一个很复杂的过程,因为这个程序要编译其他人写的代码,所以肯定需要配置很多的参数,这时我们就要用到CompilerParameters类;

changyuming的专栏 1552

C# 4.0 新增 dynamic关键字介绍

C# 4.0 新增 dynamic关键字,提供动态编程(dynamic programming),把既有的静态对象标记为动态对象,类似javascript, Python 或 Ruby。   dynamic calc = GetCalculator();   int sum = calc.Add(10, 20);   具名参数与可选参数public StreamReader ...

linuxstuding 160

WPF中Style文件的引用——使用xaml代码或者C#代码动态加载

WPF中控件拥有很多依赖属性(Dependency Property),我们可以通过编写自定义Style文件来控制控件的外观和行为,如同CSS代码一般。   总结一下WPF中Style样式的引用方法:  一、内联样式  直接在控件的内部xaml代码中书写各种依赖属性,如下:<Button Height="30" Width="60" Background="Green" Foreground="W

诗人江湖老的专栏 3万+

【飞秋】C# 调用

<br />SharpICTCLAS虽说是开源的,但07年以后就没有人再进行维护,跑搜狗的语料问题不少,就连C#版本的作者也承认有不少问题。<br /><br />即时通讯软件 想得到更为准确的分词结果,还是研究SharpICTCLAS3.0,也就是ICTCLAS 2009版。dll 文件不是C#开发的,所以引入要通过DllImport<br /><br />   先自己写了个类<br /><br />   代码<br /><br />   using System;<br /><br />   

小发猫 3099

模拟飞秋软件功能实现的编程教程

本文还有配套的精品资源,点击获取 简介:本项目旨在通过编程技术复现飞秋软件的即时通讯功能。飞秋是一款免费的局域网即时通讯工具,支持文字聊天、文件传输等功能。文章将详细介绍实现用户注册、即时消息传递、好友系统、群组聊天、文件传输、离线消息、状态显示等核心功能的编程思路与技术要点。涉及前端界面构建、后端服务器搭建、数据库管理、网络通信协议和安全性措施等技术栈的应用,并强调并发处...

weixin_33240461的博客 1094

C#中动态代码编译与执行的实现

本文还有配套的精品资源,点击获取 简介:本文介绍了一种在C# WinForms应用程序中动态编译和执行C#代码的能力。动态代码编译是在运行时根据输入或条件改变程序行为的关键技术,尤其适用于需要支持动态二次开发的场景。通过示例程序,本文阐述了使用 ***piler 命名空间中的类进行动态代码编译和执行的方法,以及如何构建用户界面以接收和运行用户代码。 ...

weixin_31486261的博客 3314

零基础教程:用AI快速搭建你的第一个飞秋应用

最让我惊喜的是平台的一键部署功能,点击按钮就能把项目部署上线,生成可访问的链接分享给朋友测试。我们的简化版只需要实现最基本的文字聊天功能:发送和接收消息。当有客户端连接时,接收消息并转发给所有连接的客户端。不需要复杂的配置,专注于代码逻辑本身,这种学习体验对新手非常友好。客户端需要连接到服务器,然后可以发送消息和接收其他客户端的消息。同样使用多线程,一个线程负责发送消息,另一个线程负责接收消息。作为一个刚接触编程的新手,我一直想尝试开发一个简单的聊天应用,但面对复杂的开发环境和框架总是望而却步。

EmeraldEagle36的博客 91

局域网通讯飞秋破解代码

用于局域网通讯,多人聊天工具,可以与飞秋同步通讯,功能与飞秋一样。

C#反射与泛型:8个高级技巧,让你的代码飞起来

反射是.NET框架提供的一个强大机制,允许程序在运行时检查和操作对象的类型信息。通过反射,我们可以动态地创建对象、调用方法、访问字段和属性等。通过本文的详细讲解和代码示例,相信你已经掌握了C#中反射和泛型的高级技巧。这些技巧不仅可以让你的代码更加灵活和高效,还能帮助你解决实际开发中遇到的各种问题。希望这篇教程对你有所帮助,期待你在C#编程中取得更大的成就!🌟✨如果你有任何问题或建议,欢迎在评论区留言交流!希望这篇教程对你有所帮助,期待你在C#编程中取得更大的成就!😊✨😊✨。

java专栏 1814

基于C#实现飞信,FeiQ的源码

基于c#的socket程序实现了飞信的功能,在此基础上,可以掌握飞鸽以及FeiQ的实现思路与原理。

c# 局域网聊天 仿飞秋和飞鸽传书

c# 实现的局域网聊天软件,可发送表情,文件。 1.参照网上若干局域网聊天软件编写而成。 2.发送消息使用UDP,传送文件使用TCP 3.用户上线时,自动发送广播消息,而后在双方好友列表里可以互相看见 4.支持更改用户名 5.默认用户名为机器名 代码里注释写得很多,初学TCP和UDP的朋友可以此做参考。 有兴趣的朋友可以在此基础上添加组播,实现群聊功能。

C#动态库创建及使用

创建动态库 1、创建项目 注意 C#工程下面由好多建立动态库的选项,要选择上图中标注的那个 2、确认net环境 注意 动态库的版本要比最终运行的环境的版本要低 3、编写代码 这步没有什么需要特别说明的,正常写就行 using System; using System.Collections.Generic; using System.Linq; using System.Text; u...

m1f2c3的专栏 2627

C#局域网聊天工具

本人是个刚学SOCKET的菜鸟,闲的没事用C#写的这个局域网聊天工具。该工具集客户端服务端与一体,主要功能聊天、传文件等。用到了多线程、socket等知识,压缩包内有源码 有需要的可以去看 共同学习 嘿嘿~~~~~

C#动态调用C++编写的DLL函数

[C#动态调用C++编写的DLL函数]        by jingzhongrong  2008-05-08动态加载DLL需要使用Windows API函数:LoadLibrary、GetProcAddress以及FreeLibrary。我们可以使用DllImport在C#中使用这三个函数。 [DllImport("Kernel32")]public static

jingzhongrong 5395

c#局域网文件传输 仿飞鸽文件

c#局域网文件传输 自动搜索IP c#局域网文件传输 自动搜索IP c#局域网文件传输 自动搜索IP c#局域网文件传输 自动搜索IP c#局域网文件传输 自动搜索IP c#局域网文件传输 自动搜索IP

PCB布线避坑指南:晶振布局的5个致命错误(附正确示例图)

本文深入解析PCB布线中晶振布局的5个致命错误,包括底层布线、电容布局、地平面处理等关键问题,并提供实战解决方案。通过真实案例和量化数据,帮助硬件开发者避免常见陷阱,提升电路稳定性和性能。特别针对晶振这一高敏感元件,给出布线参数黄金法则和三维避让原则。

weixin_29215391的博客 428

简单的使用Swig将C++标准库编写的动态库提供给C#使用方法

处于工作要求,需要把Qt和opencv编写的动态库提供给客户的的csharp程序使用,因此花时间研究了这个方法,本人的方法比较简单,就是提供一个C++标准的动态库作为桥,可以在动态库中再调用opencv和qt编写的动态库,降低了耦合度,也有利于我自己修改接口而不需要别人干预;来说步骤了1.首先需要配置swig 官网下载http://www.swig.org/官网上下载了最新的安装包 这个是我下载的...

zzc116433008的博客 3253

RK3576平台Buildroot嵌入式Linux镜像构建实战

嵌入式Linux镜像构建是连接硬件能力与软件功能的核心技术环节,其本质是基于目标SoC架构的交叉编译、内核定制与根文件系统集成过程。原理上依赖工具链适配、设备树绑定、分区镜像生成等关键步骤,技术价值在于实现轻量、确定、可复现的系统交付。典型应用场景涵盖ARM64开发板(如RK3576)、工业边缘网关及国产化信创终端。本文以TaishanPi-3为载体,深入解析Buildroot在RK3576平台上的配置裁剪、并行编译优化、genimage分区合成及update.img烧录准备,覆盖从环境选型(Ubuntu

weixin_36047538的博客 140

使用 Source Generator 代替 T4 动态生成代码

使用 Source Generator 代替 T4 动态生成代码Intro在 Source Generator 出现之前有一些重复性的代码,我会使用 T4 去生成,这样就可以一定程度上避免...

dotNET跨平台 1966

详细介绍:国产操作系统银行麒麟V10的下载和安装

银河麒麟是由。银河麒麟已经发展为银河麒麟服务器操作系统、桌面操作系统、嵌入式操作系统、麒麟云、操作系统增值产品为代表的产品线。为攻克中国软件核心技术“卡脖子”的短板,银河麒麟建设自主的开源供应链,发起中国首个开源桌面操作系统根社区openKylin,银河麒麟操作系统以openKylin等自主根社区为依托,发布最新版本。

lz17267861157的博客 1万+

从零开始:如何用Python手绘波特图并分析电路稳定性

本文详细介绍了如何使用Python绘制波特图并分析电路稳定性,涵盖从基础理论到实际应用的完整流程。通过NumPy和Matplotlib实现频域分析,包括RC低通滤波器和RLC带通滤波器的案例,以及相位裕度计算等高级技巧,为电子工程师提供了一套高效的电路分析解决方案。

hhh00的博客 374

C#调用C++的动态库技术实现方案及演示代码

P/Invoke适用于简单的函数调用,且不需要复杂的对象传递。C++/CLI适用于需要更复杂的交互,或者在C++和C#之间传递对象的情况。选择哪种方案取决于具体的需求和项目的复杂性。

yuanpan的专栏 1216

Win11大版本更新失败:系统保留分区空间不足的终极解决方案

本文针对Windows 11大版本更新时遇到的“系统保留分区空间不足”错误,提供了详细的诊断与解决方案。核心问题在于EFI系统分区(ESP)空间过小,导致更新失败。文章重点介绍了使用傲梅分区助手等第三方工具安全扩展EFI分区的完整步骤,并提供了手动清理、使用安装介质修复等替代方案,帮助用户彻底解决更新障碍,顺利完成Win11升级。

weixin_29280219的博客 964
上一篇: 【飞秋】关于结构体和结构体指针的P-INVOKE
下一篇: 平时喜欢使用的软件总结 欲善其事,必先利其器
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值