笔记:改善C#程序建议15:使用 dynamic 来简化反射实现

本文探讨了C#中使用dynamic类型简化反射操作的方法,通过对比动态类型与反射的性能,展示dynamic如何提升代码的简洁性和运行效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

改善C#程序建议1:使用 dynamic 来简化反射实现

dynamicFramework4.0 的新特性。 dynamic 的出现让C#具有了弱语言类型的特性。编译器在编译的时候不再对类型进行检査,编译器默认 dynamic 对象支持开发者想要的任何特性。例如,即使你对 GetDynamicObject方法返回的对象一无所知,也可以像如下这样进行代码的调用,编译器不会报错:

class DynamicSample
{
	public DynamicSample()
	{
		dynamic dynamicobject = GetDynamicObject();//编译器不会报错
		Console.WriteLine(dynamicobject.Name);
		Console.WriteLine(dynamicobject.SampleMethod());
	}
}

如果运行时 dynamicObject 不包含指定的这些特性(如上文中带返回值的方法 SampleMethod),运行时程序会抛出一个 RuntimeBinderException异常:“ System.Dynamic.ExpandoObject”未包含“Sample Method”的定义。

注意:var 与 dynamic 进行比较,实际上 var 和 dynamic 完全是两个概念。
var 实际上是编译期拋给我们的“语法糖”,编译期会自动匹配 var 变量的实际类型,并用实际类型来替换该变量的声明,这看上去就好像我们在编码的时候是用实际类型进行声明的。
dynamic 实际是一个 object 类型,编译器会对 dynamic 类型进行特殊处理,让它在编译期间不进行任何的类型检查,而是将类型检查放到了运行期。

利用 dynamic 的这个特性,可以简化C#中的反射语法。在 dynamic出现之前,假设存在类,代码如下所示:

class DynamicSample
{
	public string Name { get; set; }
	public int Multiply(int x , int y)
	{
		return x * y;
	}
}

1、使用反射,调用方代码如下所示:

DynamicSample dymamicsample = new DynamicSample();
var multiplyMethod = typeof(Dynamicsample.GetMethod ("Multiply");
int re = (int)multiplyMethod.Invoke(dynamicSample, new object[]{2, 10});

2、使用 dynamic,代码更简洁,并且在可控的范围内减少了一次拆箱的机会,代码如下所示:

dynamic dymamicSample2 = new Dynamicsample();
int re2 = dynamicsample2.Multiply(2, 10);

3、测试反射dynamic 性能对比:

class Program
{
	static void Main(string[] args)
	{
		DynamicSampleTest(10000);
		DynamicSampleTest(100000);
		DynamicSampleTest(1000000);
		DynamicSampleTest(10000000);
	}

	private static void DynamicSampleTest(int times)
	{
		DynamicSample reflectSample = new DynamicSample();
		var multiplyMethod = typeof(DynamicSample).GetMethod("Multiply");

		Stopwatch watch = Stopwatch.StartNew();
		for (var i = 0; i < times; i++)
		{
			multiplyMethod.Invoke(reflectSample, new object[] { 2, 10 });
		}
		Console.WriteLine(string.Format("反射优化前耗时:{0}毫秒", watch.ElapsedMilliseconds));

		var delg = (Func<DynamicSample, int,int,int>)Delegate.CreateDelegate(typeof(
			Func<DynamicSample, int, int, int>), multiplyMethod);
		Stopwatch watch2 = Stopwatch.StartNew();
		for (var i = 0; i < times; i++)
		{
			delg(reflectSample, 2, 10 );
		}
		Console.WriteLine(string.Format("反射化后耗时:{0}毫秒", watch2.ElapsedMilliseconds));

		dynamic dynamicSample = new DynamicSample();
		Stopwatch watch3 = Stopwatch.StartNew();
		for (int i = 0; i < times; i++)
		{
			dynamicSample.Multiply(2, 10);
		}
		Console.WriteLine(string.Format("dynamic耗时:{0}毫秒", watch3.ElapsedMilliseconds));
	}
}
执行10,000输出结果:执行100,000输出结果:执行1,000,000输出结果:执行10,000,000输出结果:
反射优化前耗时:2毫秒反射优化前耗时:24毫秒反射优化前耗时:225毫秒反射优化前耗时:2197毫秒
反射化后耗时:0毫秒反射化后耗时:0毫秒反射化后耗时:4毫秒反射化后耗时:46毫秒
dynamic耗时:83毫秒dynamic耗时:1毫秒dynamic耗时:13毫秒dynamic耗时:126毫秒

从测试结果对比:
反射:优化前和优化后对比相差比较大,优化前比 dynamic 性能差 ,优化后比 dynamic 性能好
dynamic:第一次初始化的时候 dynamic 耗时较高,后面随着测试量级增加也相对平稳

测试结果可以看到,优化后的反射实现,其效率和 dynamic 在一个数量级上。可是它带来效率,却牺牲代码整洁度,这种实现有点得不偿失。

建议:使用 dynamic 简化反射实现,达到优美和效率兼并。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值