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

 更新时间:2020年07月18日 08:50:31   作者:汐夜  
这篇文章主要介绍了C# 泛型中的数据类型判定与转换,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下

提到类型转换,首先要明确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关键字并不会在程序编译的时候进行校验,而只在运行时动态判定,所以使用的时需要格外小心。

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

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之后的版本才能使用该关键字,具体设置如下:

下面做一个简单测试:

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# 泛型中的数据类型判定与转换的详细内容,更多关于C# 泛型 数据类型判定与转换的资料请关注脚本之家其它相关文章!

相关文章

  • Unity3D使用右键菜单打开工程

    Unity3D使用右键菜单打开工程

    这篇文章主要为大家详细介绍了Unity3D使用右键菜单打开工程的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • C# 崩溃异常中研究页堆布局的详细过程

    C# 崩溃异常中研究页堆布局的详细过程

    最近遇到一位朋友的程序崩溃,发现崩溃点在富编辑器 msftedit 上,这个不是重点,重点在于发现他已经开启了 页堆,由于 页堆 和 NT堆 的内存布局完全不一样,这一篇结合我的了解以及 windbg 验证来系统的介绍下 页堆,需要的朋友可以参考下
    2022-10-10
  • C#操作XML通用方法汇总

    C#操作XML通用方法汇总

    这篇文章主要为大家详细介绍了C#操作XML通用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • 深入c# GDI+简单绘图的具体操作步骤(三)

    深入c# GDI+简单绘图的具体操作步骤(三)

    前两篇已经基本向大家介绍了绘图的基本知识.那么,我就用我们上两篇所学的,做几个例子.我们先来做一个简单的--仿QQ截图
    2013-05-05
  • c#异步操作async await状态机的总结(推荐)

    c#异步操作async await状态机的总结(推荐)

    这篇文章主要介绍了c#异步操作async await状态机的总结,关于async和await每个人都有自己的理解,甚至关于异步和同步亦或者关于异步和多线程每个人也都有自己的理解,本文通过实例代码详细讲解,需要的朋友可以参考下
    2023-02-02
  • C#实现对字符串进行大小写切换的方法

    C#实现对字符串进行大小写切换的方法

    这篇文章主要介绍了C#实现对字符串进行大小写切换的方法,涉及C#操作字符串的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • c#通过ip获取地理信息

    c#通过ip获取地理信息

    这篇文章主要介绍了c#通过ip获取地理信息的方法,这里是通过cz88和ip138查询的
    2014-01-01
  • C#判断一个字符串是否是数字或者含有某个数字的方法

    C#判断一个字符串是否是数字或者含有某个数字的方法

    这篇文章主要介绍了C#判断一个字符串是否是数字或者含有某个数字的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-06-06
  • C#实现将PDF转为线性化PDF

    C#实现将PDF转为线性化PDF

    线性化PDF文件是PDF文件的一种特殊格式,可以通过Internet更快地进行查看。这篇文章主要介绍了如何通过C#实现将PDF转为线性化PDF,感兴趣的小伙伴可以学习一下
    2021-12-12
  • c# 使用特定帐号密码访问Windows网路共享

    c# 使用特定帐号密码访问Windows网路共享

    这篇文章主要介绍了c# 使用特定帐号密码访问Windows网路共享的方法,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-03-03

最新评论