学无先后达者为师!
不忘初心,砥砺前行。

dotnet 使用 DynamicInternal 改善对非公开类型的访问体验

在编写一个 C# 类或者方法时,默认的可见级别是 internale 。这代表着该类型不能被其他程序集轻松访问。

新建一个类库项目 ClassLibrary1,写入以下代码:

namespace ClassLibrary1;

class BaseClass
{
    public BaseClass()
    {
        this.Id = 1024;
    }

    public int Id { get; set; }
}

新建一个控制台项目,引用 ClassLibrary1 后,写入以下代码:

using ClassLibrary1;
var myBase = new BaseClass();

最后一行代码会报错 CS0122 :

“BaseClass”不可访问,因为它具有一定的保护级别 。

CS0122

要想在控制台项目里创建 BaseClass 的实例并拿到 Id 的值,可以使用反射:

using ClassLibrary1;
var myBase = Activator.CreateInstance("ClassLibrary1", "ClassLibrary1.BaseClass").Unwrap();
var idProperty = myBase.GetType().GetProperty("Id");
int id = (int)idProperty.GetValue(myBase);
Console.WriteLine(id);

这段代码有些冗长,可以用 C# 的动态编程进行优化:

using ClassLibrary1;
var myBase = Activator.CreateInstance("ClassLibrary1", "ClassLibrary1.BaseClass").Unwrap();
dynamic dyn = myBase;
Console.WriteLine(dyn.Id);

该代码在运行时会报错:

‘object’ does not contain a definition for ‘Id’

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException

要解决这个问题,就需要请出今天的主角: DynamicInternal

DynamicInternal 的安装与使用

DynamicInternal 是 NewLife.Core 核心库中一个很轻量的类型,用于包装程序集内部类的动态对象。其代码可以在 GitHub 上找到:

https://github.com/NewLifeX/X/blob/master/NewLife.Core/Reflection/DynamicInternal.cs

你可以将代码直接复制到自己的项目中(该代码没有额外的依赖),也可以使用下面的命令添加 NuGet 引用:

dotnet add package NewLife.Core

修改后的代码如下:

using ClassLibrary1;
var myBase = Activator.CreateInstance("ClassLibrary1", "ClassLibrary1.BaseClass").Unwrap();
dynamic dyn = NewLife.Reflection.DynamicInternal.Wrap(myBase);
Console.WriteLine(dyn.Id);

总结

  1. 虽然可以通过反射的方式创建和访问非公开的类型,但是在访问非公开类型的成员时需要编写很多额外的代码。
  2. 使用动态编程可以避免代码冗长,代价是需要使用 DynamicInternal 包装一次。
  3. DynamicInternal 的功能是通过反射实现的,仍然会有使用反射时的性能问题。
  4. DynamicInternal 不支持对静态成员的访问。
赞(1) 打赏
未经允许不得转载:码农很忙 » dotnet 使用 DynamicInternal 改善对非公开类型的访问体验

评论 抢沙发

给作者买杯咖啡

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

登录

找回密码

注册