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

作者:汐夜 时间:2023-05-03 08:08:36 

提到类型转换,首先要明确C#中的数据类型,主要分为值类型和引用类型:

1.常用的值类型有:(struct)

整型家族:int,byte,char,short,long等等一系列

浮点家族:float,double,decimal

孤独的枚举:enum

孤独的布尔:bool

2.常用的引用类型有:

string,class,array,delegate,interface

值得注意的是,无论是值类型还是引用类型,在C#中都派生于object,没错,这家伙就是万恶之源!

正是因为有了这一特性,于是我们才能通过装箱和拆箱愉快地将这些数据类型在值类型,object,引用类型间反复横跳。

当然了,无论是装箱和拆箱,对于性能都是有消耗的,不到万不得已的时候尽量不要用(虽然我才不管这些,只要我用的爽就行了233)

虽然一般不提倡用object类型作为函数参数,取而代之使用泛型成为首选,那么如何判断泛型参数的具体数据类型并进行有效转换呢?

比如下面的例子:


[System.Serializable]
public struct Property<T> where T : struct
{
 public string Label { get; }
 public T Value { get; }
 public PropertyType Type { get; }
 public Property(string label, T value, PropertyType type = PropertyType.Sub)
 {
   Label = label;
   Value = value;
   Type = type;
 }

public static Property<T> operator +(Property<T> a, Property<T> b)
 {
   var prop = new Property<T>();
   if (a.Label == b.Label && a.Type == b.Type)
   {
     //怎么知道这个值到底是int还是float...
   }
   return prop;
 }
}

public enum PropertyType
{
  Main,
  Sub
}

定义了一个名叫「属性」的结构体,包含标签,具体值和属性类别(是主属性还是副属性),并使用泛型约束数据为值类型。

现在想要快速对这个结构体进行加法操作,于是增加操作符重载函数,方便愉快的对两个属性的值相加,但问题是泛型是无法强转为任何一种非object数据类型,直接相加则更是不可能。

这时就想到了以object类型作为桥梁,进行具体的类型判定与转换:


public static Property<T> operator +(Property<T> a, Property<T> b)
 {
   if (a.Label == b.Label && a.Type == b.Type)
   {
     object tempa = a.Value;
     object tempb = b.Value;

object add;
     if (tempa is int)
     {
       add = (int)tempa + (int)tempb;
     }
     else if (tempa is float)
     {
       add = (float)tempa + (float)tempb;
     }
     //...其他类型
     else
     {
       return new Property<T>();
     }

return new Property<T>(a.Label, (T)add, a.Type);
   }
   return new Property<T>();
 }

判定类型时可以使用is关键字,也可直接取得值的类型或泛型类型进行判定:


if (tempa.GetType() == typeof(float))
     {

}
     //or
     if (typeof(T) == typeof(float))
     {

}

上面的方案虽然可以解决类型转换的需求,但频繁的拆箱和装箱以及类型判定对性能的还是有一定影响,而且如果每一种类型都写进if-else,看上去像千层塔一般难受。是时候轮到dynamic登场了。

.Net 4.0 以后开始支持动态数据类型——也就是dynamic关键字;令人兴奋的是,dynamic可以被赋值为任何一种类型的值,当然也包括泛型。

然而值得注意的是,dynamic关键字并不会在程序编译的时候进行校验,而只在运行时动态判定,所以使用的时需要格外小心。

当然了,多次运行时的性能要远远高于装箱和拆箱,而且书写起来也是相当简洁美观(&macr;﹃&macr;):


public static Property<T> operator +(Property<T> a, Property<T> b)
 {
   if (a.Label == b.Label && a.Type == b.Type)
   {
     dynamic x1 = a.Value;
     dynamic x2 = b.Value;
     return new Property<T>(a.Label, (T)(x1 + x2), a.Type);
   }
   return new Property<T>();
 }

可以直接执行相加操作,但如果实际传入的两个数据类型并不能相加如bool,则会在运行时报错;当然了,如果想进一步防止安全,还可以增加更多的类型判定语句,如:


public static Property<T> operator +(Property<T> a, Property<T> b)
 {
   if (a.Label == b.Label && a.Type == b.Type)
   {
     if (typeof(T) != typeof(bool) && typeof(T)!=typeof(Enum))
     {
       dynamic x1 = a.Value;
       dynamic x2 = b.Value;
       return new Property<T>(a.Label, (T)(x1 + x2), a.Type);
     }
   }
   return new Property<T>();
 }

补充一句,dynamic关键字在Unity中可能会报错,因为Unity默认用的是.Net Api为2.0版本,需要升级为4.0之后的版本才能使用该关键字,具体设置如下:

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

下面做一个简单测试:


using UnityEngine;

public class MicrosoftCSharpTest : MonoBehaviour
{
 void Start()
 {
   dynamic a = 5.1f;
   dynamic b = 3;
   Debug.Log(a + b);

var hp1 = new Property<int>("Hp", 41);
   var hp2 = new Property<int>("Hp", 5);
   var hp = hp1 + hp2;
   Debug.Log(hp.Label + " : " + hp.Value);

var miss1 = new Property<float>("MissRate", .1f);
   var miss2 = new Property<float>("MissRate", .05f);
   var miss = miss1 + miss2;
   Debug.Log(miss.Label + " : " + miss.Value);
 }
}

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

来源:https://www.cnblogs.com/koshio0219/p/13331278.html

标签:c#,泛型,数据类型,判断,转换
0
投稿

猜你喜欢

  • 解决java执行cmd命令调用ffmpeg报错Concat error - No such filter '[0,0]'问题

    2023-03-14 20:35:11
  • java实现简单扫雷游戏

    2022-09-15 13:48:11
  • Android抛物线下载动画制作过程

    2022-05-15 21:39:57
  • SpringBoot自定义starter实例代码

    2021-09-04 14:28:06
  • Android SlidingDrawer 抽屉效果的实现

    2023-08-02 07:58:30
  • 4种Android屏幕自适应解决方案

    2022-09-09 07:28:42
  • 深入解析Java的Spring框架中的混合事务与bean的区分

    2021-12-28 19:48:41
  • Android ListView 实现上拉加载的示例代码

    2021-09-16 18:04:17
  • Spring MVC 简单的hello world的实现

    2023-06-18 02:56:41
  • Java服务器主机信息监控工具类的示例代码

    2023-07-26 04:34:49
  • Java并发编程之原子性-Atomic的使用

    2023-11-09 22:34:58
  • Flutter实现固定header底部滑动页效果示例

    2022-06-15 06:31:05
  • android 将图片压缩到指定的大小的示例

    2021-07-29 23:09:23
  • Java新手环境搭建 JDK8安装配置教程

    2023-11-25 17:23:10
  • java jdbc连接和使用详细介绍

    2023-01-13 18:12:52
  • java中javamail收发邮件实现方法

    2022-12-15 02:03:03
  • Java用三元运算符判断奇数和偶数的简单实现

    2023-07-24 16:54:03
  • Spring的@Autowired加到接口上但获取的是实现类的问题

    2023-08-23 21:32:21
  • 利用Java实现简单的词法分析器实例代码

    2023-10-06 08:14:45
  • Spring Security使用Lambda DSL配置流程详解

    2021-12-23 19:20:32
  • asp之家 软件编程 m.aspxhome.com