找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2264|回复: 9

C# 泛型中的数据类型判定与转换

  [复制链接]
  • 打卡等级:即来则安
  • 打卡总天数:29
  • 打卡月天数:1
  • 打卡总奖励:7791
  • 最近打卡:2025-12-13 17:25:16

2540

主题

1355

回帖

2万

积分

管理员

积分
21304
发表于 2021-5-19 20:35:52 | 显示全部楼层 |阅读模式
提到类型转换,首先要明确C#中的数据类型,主要分为值类型和引用类型:
1.常用的值类型有:(struct)
整型家族:int,byte,char,short,long等等一系列
浮点家族:float,double,decimal
孤独的枚举:enum
孤独的布尔:bool
2.常用的引用类型有:
string,class,array,delegate,interface
值得注意的是,无论是值类型还是引用类型,在C#中都派生于object,没错,这家伙就是万恶之源!
正是因为有了这一特性,于是我们才能通过装箱和拆箱愉快地将这些数据类型在值类型,object,引用类型间反复横跳。
当然了,无论是装箱和拆箱,对于性能都是有消耗的,不到万不得已的时候尽量不要用(虽然我才不管这些,只要我用的爽就行了233)
虽然一般不提倡用object类型作为函数参数,取而代之使用泛型成为首选,那么如何判断泛型参数的具体数据类型并进行有效转换呢?
比如下面的例子:
1 [System.Serializable] 2 public struct Property<T> where T : struct 3 { 4     public string Label { get; } 5     public T Value { get; } 6     public PropertyType Type { get; } 7     public Property(string label, T value, PropertyType type = PropertyType.Sub) 8     { 9         Label = label;10         Value = value;11         Type = type;12     }13 14     public static Property<T> operator +(Property<T> a, Property<T> b)15     {16         var prop = new Property<T>();17         if (a.Label == b.Label && a.Type == b.Type)18         {19             //怎么知道这个值到底是int还是float...20         }21         return prop;22     }23 }1 public enum PropertyType2 {3     Main,4     Sub5 }
定义了一个名叫「属性」的结构体,包含标签,具体值和属性类别(是主属性还是副属性),并使用泛型约束数据为值类型。
现在想要快速对这个结构体进行加法操作,于是增加操作符重载函数,方便愉快的对两个属性的值相加,但问题是泛型是无法强转为任何一种非object数据类型,直接相加则更是不可能。
这时就想到了以object类型作为桥梁,进行具体的类型判定与转换:
1     public static Property<T> operator +(Property<T> a, Property<T> b) 2     { 3         if (a.Label == b.Label && a.Type == b.Type) 4         { 5             object tempa = a.Value; 6             object tempb = b.Value; 7  8             object add; 9             if (tempa is int)10             {11                 add = (int)tempa + (int)tempb;12             }13             else if (tempa is float)14             {15                 add = (float)tempa + (float)tempb;16             }17             //...其他类型18             else19             {20                 return new Property<T>();21             }22 23             return new Property<T>(a.Label, (T)add, a.Type);24         }25         return new Property<T>();26     }
判定类型时可以使用is关键字,也可直接取得值的类型或泛型类型进行判定:
1             if (tempa.GetType() == typeof(float))2             {3 4             }5             //or6             if (typeof(T) == typeof(float))7             {8 9             }
上面的方案虽然可以解决类型转换的需求,但频繁的拆箱和装箱以及类型判定对性能的还是有一定影响,而且如果每一种类型都写进if-else,看上去像千层塔一般难受。是时候轮到dynamic登场了。
.Net 4.0 以后开始支持动态数据类型——也就是dynamic关键字;令人兴奋的是,dynamic可以被赋值为任何一种类型的值,当然也包括泛型。
然而值得注意的是,dynamic关键字并不会在程序编译的时候进行校验,而只在运行时动态判定,所以使用的时需要格外小心。
当然了,多次运行时的性能要远远高于装箱和拆箱,而且书写起来也是相当简洁美观(¯﹃¯):
1     public static Property<T> operator +(Property<T> a, Property<T> b) 2     { 3         if (a.Label == b.Label && a.Type == b.Type) 4         { 5             dynamic x1 = a.Value; 6             dynamic x2 = b.Value; 7             return new Property<T>(a.Label, (T)(x1 + x2), a.Type); 8         } 9         return new Property<T>();10     }
可以直接执行相加操作,但如果实际传入的两个数据类型并不能相加如bool,则会在运行时报错;当然了,如果想进一步防止安全,还可以增加更多的类型判定语句,如:
1     public static Property<T> operator +(Property<T> a, Property<T> b) 2     { 3         if (a.Label == b.Label && a.Type == b.Type) 4         { 5             if (typeof(T) != typeof(bool) && typeof(T)!=typeof(Enum)) 6             { 7                 dynamic x1 = a.Value; 8                 dynamic x2 = b.Value; 9                 return new Property<T>(a.Label, (T)(x1 + x2), a.Type);10             }11         }12         return new Property<T>();13     }
补充一句,dynamic关键字在Unity中可能会报错,因为Unity默认用的是.Net Api为2.0版本,需要升级为4.0之后的版本才能使用该关键字,具体设置如下:


下面做一个简单测试:
1 using UnityEngine; 2  3 public class MicrosoftCSharpTest : MonoBehaviour 4 { 5     void Start() 6     { 7         dynamic a = 5.1f; 8         dynamic b = 3; 9         Debug.Log(a + b);10 11         var hp1 = new Property<int>("Hp", 41);12         var hp2 = new Property<int>("Hp", 5);13         var hp = hp1 + hp2;14         Debug.Log(hp.Label + " : " + hp.Value);15 16         var miss1 = new Property<float>("MissRate", .1f);17         var miss2 = new Property<float>("MissRate", .05f);18         var miss = miss1 + miss2;19         Debug.Log(miss.Label + " : " + miss.Value);20     }21 }

本文作者:汐夜
原文地址
:https://www.cnblogs.com/koshio0219/p/13331278.html

工控课堂 www.gkket.com

0

主题

148

回帖

405

积分

注册会员

积分
405
发表于 2021-5-19 20:35:53 | 显示全部楼层
我只是路过打酱油的。
工控课堂 www.gkket.com

0

主题

87

回帖

218

积分

注册会员

积分
218
发表于 2021-5-19 22:01:27 | 显示全部楼层
看了楼主的帖子,不由得精神一振,豁然开朗,牛掰
工控课堂 www.gkket.com

0

主题

1451

回帖

4571

积分

金牌会员

积分
4571
发表于 2025-11-24 13:09:22 | 显示全部楼层
求个链接 / 教程,楼主好人一生平安~
工控课堂 www.gkket.com

0

主题

131

回帖

304

积分

注册会员

积分
304
发表于 2025-11-24 13:25:06 | 显示全部楼层
水贴也要有仪式感,我先来打卡~
工控课堂 www.gkket.com

0

主题

99

回帖

154

积分

新手上路

积分
154
发表于 2025-11-24 13:26:29 | 显示全部楼层
不请自来,就想夸一句:太顶了!
工控课堂 www.gkket.com

0

主题

81

回帖

122

积分

新手上路

积分
122
发表于 2025-11-24 13:34:53 | 显示全部楼层
这评论区卧虎藏龙,个个都是人才!
工控课堂 www.gkket.com

0

主题

81

回帖

123

积分

新手上路

积分
123
发表于 2025-11-24 13:37:09 | 显示全部楼层
理性围观,感觉大家说的都有道理~
工控课堂 www.gkket.com

0

主题

254

回帖

2296

积分

高级会员

积分
2296
发表于 2025-11-24 19:48:00 | 显示全部楼层
赞同 + 10086,完全说出了我的想法!
工控课堂 www.gkket.com

0

主题

85

回帖

126

积分

新手上路

积分
126
发表于 2025-11-24 20:16:28 | 显示全部楼层
水个经验,支持楼主,加油呀
工控课堂 www.gkket.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|手机版|免责声明|本站介绍|工控课堂 ( 沪ICP备20008691号-1 )

GMT+8, 2025-12-22 20:53 , Processed in 0.088315 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表