C#中的救火队员dynamic

275 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

文章标题皮一下,很开心...
言归正传,之所以这样说,是因为我在使用C#处理一些项目中遇到的实际问题中,有一次真遇到一个棘手的问题,坐立不安,无从下手去解决时,翻了半天搜索引擎,一看到dynamic,问题就迎刃而解了!
所以,我取这个名称不过分吧[dog]

其实这个dynamic在C#这样的后端语言中是个编外者,相当于强类型语言中的弱类型,存在即合理吧。

dynamic类型并不是C#语言一开始就有的,说明有需要他的地方,比如说帮我救火的场景中...

救火场景:List类型数据 动态添加属性值

按说这种问题都不是我一个后端该干的活,我数据查询出来,直接甩前端,怎么处理是他的事,他却说我给他的数据有问题,缺少字段信息,让我处理好再给他,不然....奈何他亲戚是领导,罢了罢了,只能把摸鱼时间拿出来帮他处理一下再甩他(屈服理由瞎编的,爱信不信....)

工作场景中具体场景就不说了,差不多相当于List中新增一个动态属性值,这个值是根据T中的其他几个属性值经过一系列计算后得出来的,然后拼接或其他复杂操作后,达到前端拿过去可以直接渲染的效果。
这里用一个简单的例子说明下
比如,给对象中添加一个序号信息(注:真实情况中,这个序号在前端直接可以用数组下标即可,这里仅仅是举例

List<User> users = new List<User>();
var order = 0;
foreach (var item in res)
{
    var obj = item.ToDynamic();
    obj.Order = order++;
    users.Add(obj);
}
return users;

//相对简洁一点的写法,借用Select
return res.Select(x =>
{
    var r = x.ToDynamic();
    r.Order = order++;
    return r;
}).ToList();

想想,如果没有dynamic,要后端来处理这种需求还是有点小复杂的

dynamic vs var

var属于临时给变量一个容器,这个容器在变量初始化后即确定了变量的类型!\

而dynamic相当于一个万能容器,不管放什么类型都可以,程序也不会去管它(强类型语言不会对它的类型进行检查抛异常等),只有在程序编译运行时,编译器才会预判它存的到底是个什么玩意,然后进行相应的处理...

变量初始化上的区别问题

先写三个变量

int ab = default;
var sc = default;
dynamic zs = default;

上面代码有问题吗?
是的,真有问题,中间一个会直接报错 image.png

因为var 在声明一个变量时必须初始化,否则在C#这种强类型语言中会直接报错处理
而int ab其实已经初始化了因为他已经确定了变量的类型,这个int有默认值,就是 0(基础数据类型,都有默认值,这是最基础的....)
dynamic zs并不会报错,虽然他也没有初始化,也没有确定变量的类型,但是他是在运行中才去解析的,否则程序并不会去判定他的类型,所以没有问题。

初始化问题代码

static void Main(string[] args)
{
    List<User> user1 = default;
    dynamic user2 = default;

    user1.Add(User.GetUser());
    user2.Add(User.GetUser());

    Console.ReadLine();
}

class User
{
    public string Name { get; set; }

    public int Age { get; set; }

    public static User GetUser()
    {
        var arr = new string[] { "aaa", "bbb", "ccc", "ddd", "eee" };
        var rand = new Random();
        return new User { Name = arr[rand.Next(5)], Age = rand.Next(1, 99) };
    }
}

猜一下这两种写法有没有问题?为什么?
不出意料,两种写法都有问题,但是报错的点不同,详情看图 image.png

报错:对象引用没有设置为一个对象的实例。

image.png

报错:无法对一个空引用执行运行时绑定

其实两个报错性质是一样的,只是时机不一样而已!
实例证明,default并不适用与引用类型变量的初始化操作,仅适用于普通的值类型

如下代码操作,会报错吗?

dynamic user = User.GetUser();
user = 666;
Console.WriteLine(user);

并不会报错,正常运行,这C#写的跟js没区别了...

image.png

上例:证明dynamic拥有弱类型语言的特性 + 运行时编译最后再确定其类型的,且其类型可动态变化

文末总结

强中自有强中手,再强也需要有弱的一面,不然怎么提现出他的完美。
dynamic就是C#中的弱,有了他的存在,使得c#具备了弱类型特性!