DLR

在.NET Framework中,DLR2位于System.Dynamic命名空间和System.Runtime.CompilerServices命名空间的几个类中。

dynamic 类型

可以发现staticPerson出现了编译错误,而dynamicPerson并没有,因为定义为dynamic的对象可以在运行期改变其类型,甚至改变多次,这与强制转换类型是不一样的,它在编译期不会做检查。

对于dynamic 类型有两个限制:动态对象不支持扩展方法,匿名函数(lambda表达式)也不能用于动态方法调用参数,因此LINQ不能用于动态对象。大多数LINQ调用都是扩展方法,而lambda表达式用作这些扩展方法的参数。

包含DLR ScriptRuntime

项目通过NuGet安装IronPython,然后using Microsoft.Scripting.Hosting,就有了ScriptRuntime

就可以执行存储在文件中 的代码段或完整的脚本。

例:

xaml文件

<Window x:Class="DiscountWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DiscountWPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="300">
<Grid AutomationProperties.HelpText="disc based on cost">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions> <RadioButton x:Name="CostRadioButton" Grid.Row="0" VerticalAlignment="Center" >Disc Based on Cost</RadioButton>
<RadioButton x:Name="NumRadioButton" Grid.Row="1" VerticalAlignment="Center" >Disc Based on No of Items</RadioButton>
<StackPanel Grid.Row="2" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock>Total No of Items:</TextBlock>
<TextBox x:Name="totalItems" Width="180" HorizontalContentAlignment="Right"/>
</StackPanel>
<StackPanel Grid.Row="3" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock>Total Amount</TextBlock>
<TextBox x:Name="totalAmount" Width="178" HorizontalAlignment="Left" VerticalAlignment="Center" HorizontalContentAlignment="Right"/>
</StackPanel>
<StackPanel Grid.Row="7" Orientation="Vertical" VerticalAlignment="Center">
<Button x:Name="calDisc" Content="Calc Discount" Width="100" Click="calDisc_Click"/>
<Button x:Name="calTax" Content="Cal Tax" Width="100" Margin="0,10,0,0" Click="calTax_Click"/>
</StackPanel>
<StackPanel Grid.Row="4" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock>Discounted Amount:</TextBlock>
<TextBlock x:Name="label"></TextBlock>
</StackPanel>
<StackPanel Grid.Row="5" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock>Amount with Tax:</TextBlock>
<TextBlock x:Name="labelA"></TextBlock>
</StackPanel>
</Grid>
</Window>
using Microsoft.Scripting.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes; namespace DiscountWPF
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
} private void calDisc_Click(object sender, RoutedEventArgs e)
{
string scriptToUse;
if (CostRadioButton.IsChecked.Value)
{
scriptToUse = "AmountDisc.py";
}
else
{
scriptToUse = "CountDisc.py";
}
ScriptRuntime scriptRuntime = ScriptRuntime.CreateFromConfiguration();
ScriptEngine pythEng = scriptRuntime.GetEngine("python");
ScriptSource source = pythEng.CreateScriptSourceFromFile(scriptToUse);
ScriptScope scope = pythEng.CreateScope();
scope.SetVariable("prodCount", Convert.ToInt32(totalItems.Text));
scope.SetVariable("amt", Convert.ToDecimal(totalAmount.Text));
source.Execute(scope);
label.Text = scope.GetVariable("retAmt").ToString();
} private void calTax_Click(object sender, RoutedEventArgs e)
{
ScriptRuntime scriptRuntime = ScriptRuntime.CreateFromConfiguration();
dynamic calcRatet = scriptRuntime.UseFile("CalcTax.py");
labelA.Text = calcRatet.CalcTax(Convert.ToDecimal(label.Text)).ToString();
}
}
}

从代码可知,ScriptRuntime对象是通过配置文件来产生的,因为调用了ScriptRuntime.CreateFromConfiguration()方法产生的,因此,本项目的App.config如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="microsoft.scripting" type="Microsoft.Scripting.Hosting.Configuration.Section, Microsoft.Scripting"/>
</configSections>
<microsoft.scripting>
<languages>
<language names="IronPython;Python;py" extensions=".py" displayName="Python" type="IronPython.Runtime.PythonContext, IronPython"/>
</languages>
</microsoft.scripting>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
</configuration>

Calc Discount按钮的click事件调用的方法是通过依次创建ScriptRuntimeScriptEngineScriptSource,ScriptScope对象,对ScriptSource进行执行,从ScriptScope设定变量的值,获取变量的值。

Cal Tax按钮的click事件调用的 方法是创建ScriptRuntime,然后通过该对象的UseFile方法,得到Dynamic类型对象,然后通过该动态对象,调用脚本中的方法。

CountDisc.py

discCount=5
discAmt=0.1
retAmt=amt
if(prodCount>discCount):
retAmt=amt-(amt*discAmt)

AmountDisc.py

discAmt=0.25
retAmt=amt
if amt>25:
retAmt=amt-(amt*discAmt)

CalTax.py

def CalcTax(amount):
return amount*1.075

DynamicObject和ExpandoObject

  • DynamicObject

创建自己的动态对象,要么从DynamicObject中派生,也要么使用ExpandoObject

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace DynamicDemo
{
class Program
{
static void Main(string[] args)
{
dynamic wroxDyn = new WroxDynamicObject();
wroxDyn.FirstName = "John";
wroxDyn.LastName = "Yang";
Console.WriteLine(wroxDyn.GetType());
Console.WriteLine("{0}--{1}", wroxDyn.FirstName, wroxDyn.LastName);
Func<DateTime, string> GetTomo = today => today.AddDays(1).ToShortDateString();
wroxDyn.GetTomorrow = GetTomo;
Console.WriteLine("Tomorrow is {0}", wroxDyn.GetTomorrow(DateTime.Now));
}
}
class WroxDynamicObject : DynamicObject
{
Dictionary<string, object> _dynamicData = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
bool success = false;
result = null;
if (_dynamicData.ContainsKey(binder.Name))
{
result = _dynamicData[binder.Name];
success = true;
}
else
{
result = "Property not found"; }
return success;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_dynamicData[binder.Name] = value;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
dynamic method = _dynamicData[binder.Name];
result = method((DateTime)args[0]);
return result != null;
}
} }

output

DynamicDemo.WroxDynamicObject
John--Yang
Tomorrow is 2022/2/5
  • ExpandoObject

ExpandoObject不用重写方法,可以直接使用,如果需要控制动态对象中属性的添加和访问,则使用DynamicObject是最佳选择,其他情况,则使用dynamic或者ExpandoObject。

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace DynamicDemo
{
class Program
{
static void Main(string[] args)
{
dynamic wroxDyn = new ExpandoObject();
wroxDyn.FirstName = "John";
wroxDyn.LastName = "Yang";
Console.WriteLine(wroxDyn.GetType());
Console.WriteLine("{0}--{1}", wroxDyn.FirstName, wroxDyn.LastName);
Func<DateTime, string> GetTomo = today => today.AddDays(1).ToShortDateString();
wroxDyn.GetTomorrow = GetTomo;
Console.WriteLine("Tomorrow is {0}", wroxDyn.GetTomorrow(DateTime.Now));
}
}
}

output

System.Dynamic.ExpandoObject
John--Yang
Tomorrow is 2022/2/5

利用ExpandoObject,来储存任意数据类型的数据的一个Demo:

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace DynamicDemo
{
class Program
{
static void Main(string[] args)
{
var retList = new List<dynamic>();
dynamic expObj=new ExpandoObject();
((IDictionary<string, object>)expObj).Add("john", 10);
retList.Add(expObj);
dynamic expObj1 = new ExpandoObject();
((IDictionary<string, object>)expObj1).Add("yang", DateTime.Now);
retList.Add(expObj1);
foreach(var dy in retList)
{
var tempDic = (IDictionary<string, object>)dy;
foreach(var kv in tempDic)
{
Console.WriteLine(kv.Key);
Console.WriteLine(kv.Value);
}
} }
} }

output

john
10
yang
2022/2/4 23:35:21

C#之动态语言扩展的更多相关文章

  1. Azure Table storage 之改进DynamicTableEntity类为其添加动态语言扩展

    在之前的一篇文章中提到,storage类库中包含一个可以用来动态获取Azure table storage 表结构的类-DynamicTableEntity. 我们可以通过这个类,我们无需为每一个表提 ...

  2. C#高级编程9-第12章 动态语言扩展

    C#高级编程9-第12章 动态语言扩展 dynamic t = new ExpandoObject(); t.Abc = "abc"; t.Value = ; Console.Wr ...

  3. C# 动态语言扩展(11)

    在 C# 4 开始添加 dynamic 类型.Mono C# 已经支持 C# 6.0 了. DLR C# 4 动态功能是 Dynamic Language Runtime (动态语言运行时,DLR)的 ...

  4. 【读书笔记】C#高级编程 第十二章 动态语言扩展

    (一)DLR C#4的动态功能是Dynamic Language Runtime(动态语言运行时,DLR)的一部分.DLR是添加到CLR的一系列服务. (二)dynamic类型 dynamic类型允许 ...

  5. C语言扩展动态内存报错:realloc(): invalid next size: 0x0000000002365010 ***

    晚上被这个内存扩展崩溃的问题折腾的有点崩溃,当答案揭晓的那一刻,恍然大悟,原来如此简单. 练习题目:输入一个字符串,根据字母进行排序,说白了就是一个简单的冒泡 #include <stdio.h ...

  6. Web服务器和动态语言如何交互--CGI&FastCGI&FPM浅谈

    一个用户的Request是如何经过Web服务器(Apache,Nginx,IIS,Light)与后端的动态语言(如PHP等)进行交互并将结果返回给用户的呢? 本文浅谈个人观点,可能有误,欢迎拍砖,共同 ...

  7. C# 动态语言特性,dynamic 关键字研究

    1       动态语言简介 支持动态特性的语言现在大行其道,并且有继续增长的趋势.比如 Ruby 和 Python, 还有天王级的巨星 --- JavaScript. 现在一个程序员说自己对 Jav ...

  8. javascript语言扩展:可迭代对象(3)

    除了前2篇文章中描述的可迭代对象以外,在js语言扩展中的生成器对象,也可以作为可迭代对象. 这里用到一个新的关键字yield,该关键字在函数内部使用,用法和return类似,返回函数中的一个值:yie ...

  9. JVM中的动态语言支持简介

    抽丝剥茧 细说架构那些事——[优锐课] 从版本6开始,JVM已扩展为支持现代动态语言(也称为脚本语言).Java8的发行为这一领域提供了更多动力.感到这种支持的必要性是因为Java作为一种语言固有地是 ...

  10. 动态语言运行时(DLR)

    前言 为了让C#.Visual Basic等.NET编程语言能具备动态编程语言的特性,.NET 4.0引入了一个"DLR(Dynamic Language Runtime:动态语言运行时)& ...

随机推荐

  1. 八米云-各种小主机x86系统-小白保姆式超详细刷机教程

    疑难解答加微信机器人,给它发:进群,会拉你进入八米交流群 机器人微信号:bamibot 简洁版教程访问:https://bbs.8miyun.cn 准备工作 说明: 1.小节点X86 单线500M以下 ...

  2. HTTP - [01] 简介

    HTTP本身是不安全的,因为传输的数据未经加密,可能会被窃听或篡改.为了解决这个问题,引入了HTTPS,即在HTTP上加入SSL/TLS协议,为数据传输提供了加密和身份验证. 一.概述   HTTP( ...

  3. 单元测试三部曲-AAA模式

    AAA 指的是 "Arrange, Act, Assert",这是一种通用的单元测试模式. 在测试方法中, 1.首先对测试对象进行准备(Arrange), 2.然后调用要测试的方法 ...

  4. TVbox蜂蜜影视_v3.1.6:智能电视观影新选择,简洁界面与强大功能兼具

    蜂蜜影视是一款基于猫影视开源项目 CatVodTVJarLoader 开发的智能电视软件,专为追求简洁与高效观影体验的用户设计.该软件从零开始编写,界面清爽,操作流畅,特别适合在智能电视上使用.其最大 ...

  5. VMware虚拟机上安装CentOS8详细教程

    1.准备工作 1.1.需要准备好已安装完成的VMware虚拟机,如果您的电脑未安装VMware虚拟机,请参考以下连接:https://www.cnblogs.com/x1234567890/p/148 ...

  6. C++ open()和read()函数使用详解

    对于Framework工程师来说,必要C或者C++编程能力是必须的,像对设备节点的操作是最基本的操作,那么我们便会用到open和read函数.open()函数用于打开文件,而read()函数用于从打开 ...

  7. 循环(Java篇)

    令人头痛的循环(:´д`)ゞ 我们在学习循环的时候可能会有点懵,什么是循环?它可以干嘛?我这里为什么要用循环来写这段代码?等问题. 首先我们来讲一下循环可以干嘛 循环是什么?o(′益`)o 在 Jav ...

  8. Web前端入门第2问:前端开发是什么?与后端、全栈的区别是什么?一个完整的Web项目有哪些角色参与?

    一个完整的Web项目有哪些角色参与? 提出需求(这一步可以是甲方,也可以是用户) 需求分析,画出原型图(产品经理) 根据原型图输出 UI 界面及交互图(UI/UX设计师) 根据UI及交互效果画出页面, ...

  9. s = 0.5 * a * Math.pow(t,2),关于js动画,从一个公式说起

    s = 0.5 * a* t*t 上边这个是高中物理课本关于位移的计算公式,位移等于二分之一乘以a乘以t的平方,a是加速度,t是运动进行的时间(当然啦,初速度为0).下面我们会应用这个公式完成一个js ...

  10. BUUCTF---佛说:只能四天

    题目 尊即寂修我劫修如婆愍闍嚤婆莊愍耨羅嚴是喼婆斯吶眾喼修迦慧迦嚩喼斯願嚤摩隸所迦摩吽即塞願修咒莊波斯訶喃壽祗僧若即亦嘇蜜迦須色喼羅囉咒諦若陀喃慧愍夷羅波若劫蜜斯哆咒塞隸蜜波哆咤慧聞亦吽念彌諸嘚嚴諦咒 ...