zoukankan      html  css  js  c++  java
  • 【.net深呼吸】动态类型(娱乐篇)

    有朋友跟老周说,动态类型是干吗的,他不太熟悉,希望老周可以讲一讲。没事,这事情老周也比较TMD乐意做的,因为老周写的这些烂文本来就是为了普及基础知识的,坚定不移地为社会基础教育而服务。

    首先,咱们要知道啥是动态类型,既然叫“动态”了,当然和“静态”相对而言的,但你得注意,这里的动态静态不是指类型的动与静,不要以为动态类型就是实例类型,也不要认为静态类型就是static关键定义的类型。

    非也,这里所讨论的dynamic是指在编译阶段不做解析和检查,而在运行阶段才调用的类型。你不要在意书本上讲得多么抽象难懂,你记得这句话就行了,编译是啥,你懂吧,那就好了。

    动态技术可以用起来很简单,也可以很复杂,重点是看你怎么用罢了。如果你需要完全自定义动态的行为,当然得很复杂,因为你要自己来实现动态操作的逻辑。

    本次老周就先讲一些简单的,故称为“娱乐篇”,改天,再说说“高级篇”,看看怎么自定义动态行为。

    在C#语言中,用dynamic关键字来声明动态类型,实例化时你可以赋任意值。比如这样:

                dynamic d = 3000u;
                Console.WriteLine(d.GetType());
    
                dynamic m = "子曰:有朋自远方来,记得请吃饭";
                Console.WriteLine(m.GetType());

    变量d和m都被声明为动态的,你猜这几行代码运行后会输出什么。dynamic关键字声明的变量可以赋任何类型的值。比如这个例子,d赋的uint类型的值3000,后面的u就表示这个数值是uint类型;m赋的是字符串值。因此,在运行阶段,会根据变量中具体的值来判断其类型,d变量存放的值的类型为System.UInt32,m存放的值类型为System.String。

    所以,输出的内容为:

    System.UInt32
    System.String

    你还可以向动态类型的属性赋值,属性名都是动态生成的,所以在输入时是没有智能提示的,因为是运行时才解析,所以,赋值和取值时的属性名字一定要一致,不然就取不到值了。

    举个例子:

                dynamic dd = new ExpandoObject();
                // 赋值
                dd.Name = "小王";
                dd.Age = 35;
    
                // 取值
                Console.WriteLine($"此人名叫 {dd.Name} ,年龄 {dd.Age}。");

    ExpandoObject是专为动态行为而设计的类型,因为此时要向动态类型的实例的属性赋值,因此属于复合类型,在用dynamic关键字声明变量后,就必须用一个类来实例化,ExpandoObject类就是这个用途。

    然后,赋了Name和Age属性的值,属性名字可以随便写,因为是动态的,编译时不会检查;然后在读取属性的值时,属性名一定要和刚才赋值时的名字一致,不然你是取不到值的。

    所以得到结果如下:

    此人名叫 小王 ,年龄 35。

    实际上,ExpandoObject类显式实现了 IDictionary<string,object> 接口,所以,我们可以知道,其实它里面就是用一个字典来存储动态赋值的数值的,键的类型为字符串,表示属性名;值的类型为object,表示任何类型。

    不信?咱们把它里面的字典数据输出来:

                IDictionary<string, object> dic = (IDictionary<string, object>)dd;
                foreach (var pv in dic)
                {
                    Console.WriteLine($"Key = {pv.Key} , Value = {pv.Value}");
                }

    然后得到结果如下:

    Key = Name , Value = 小王
    Key = Age , Value = 35

    所为为什么不管你如何动态设置属性,它都可以进行解析,就是这个原因,里面用一个字典来负责存取数据。

    由于这个类也实现了INotifyPropertyChanged接口,所以,还可以用它来做数据绑定。

    看例子:在WPF中用动态对象来进行双向绑定。

    XAML如下:

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <StackPanel Grid.Row="0" Name="panel1">
                <TextBlock Text="{Binding Path=Text1,Mode=OneWay}"/>
                <TextBlock Text="{Binding Path=Text2,Mode=OneWay}"/>
            </StackPanel>
            <StackPanel Grid.Row="1" Name="panel2">
                <TextBox Text="{Binding Path=Text1,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                <TextBox Text="{Binding Path=Text2,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
            </StackPanel>
        </Grid>

    然后在代码中初始化动态对象,并让这两个StackPanel的DataContext都引用同一个动态对象实例。

            dynamic obj = null;
            public MainWindow()
            {
                InitializeComponent();
                // 初始化
                obj = new ExpandoObject();
    
                obj.Text1 = "item 1";
                obj.Text2 = "item 2";
    
                this.panel1.DataContext = this.panel2.DataContext = obj;
            }

    运行之后,在下面的两个TextBox中输入内容,然后你会看到上面的TextBlock中的文本也会跟着一起变化。

    好,今天老周给大家说了动态对象的一些娱乐级别的功能,用起来挺简单方便。过几天有空,再给大伙儿们说说高端篇,介绍如何自己来实现支持动态行为的类型。

    示例代码下载

  • 相关阅读:
    C# 各种数据类型的最大值和最小值常数
    使用EntityFramework6连接MySql数据库(db first方式)
    apache ignite系列(八):问题汇总
    apache ignite系列(六): 服务网格
    golang实现get和post请求的服务端和客户端
    python+selenium调用chrome打开网址获取内容
    spring-boot集成spark并使用spark-sql
    apache ignite系列(五):分布式计算
    sqoop导oracle数据到hive中并动态分区
    python使用cx_Oracle连接oracle
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/5110658.html
Copyright © 2011-2022 走看看