详解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关键字并不会在程序编译的时候进行校验,而只在运行时动态判定,所以使用的时需要格外小心。
当然了,多次运行时的性能要远远高于装箱和拆箱,而且书写起来也是相当简洁美观(¯﹃¯):
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);
}
}
来源:https://www.cnblogs.com/koshio0219/p/13331278.html
猜你喜欢
- TV 3D卡片无限循环效果,供大家参考,具体内容如下##前言1、需求:实现3个卡片实现无限循环效果:1-2-3-1-2-3-1…,而且要实现
- 前言《飞机大战-I》是一款融合了街机、竞技等多种元素的经典射击手游。华丽精致的游戏画面,超炫带感的技能特效,超火爆画面让你肾上腺素爆棚,给你
- 1、引例class Complex{private: double Real,Image;public: &nbs
- 一.什么是泛型当我们不确定数据类型时,我们可以暂时使用一个字母 T代替数据类型。例如写一个方法,但是我们不知道它是传递的是什么数据类型,我们
- 《IDEA 破解新招 - 无限重置30天试用期》,这种方法适用idea2021以下所有版本,亲测idea2020.3成功激活,其他版本自测吧
- 项目地址:https://github.com/JeasonWong/SlackLoadingView老规矩,先上效果。图好大。。说下第一眼
- 为什么要给图片添加水印为图片添加水印的主要作用是保护图片版权,防止图片被未经授权的人使用或传播。通常情况下,图片水印会包含图片作者的名字、版
- 一、定义委托delegate void StudentDelegate();//【1】定义一个委托二、定义一个调用和定义事件的类/// &l
- 背景我们项目一开始的所有提示都是中文,后来要做国际化。发现项目中的带双引号的中文居然有 2.3 w 多条!!!简直让人欲
- spring Cache注解和redis区别1.不支持TTL即不能设置过期时间 expires time,SpringCache 认为这是各
- springboot初始化器新建项目项目结构idea工具类中初始化本地git仓库选择当前项目目录即可工具类由VCS变成了Gitadd 到缓存
- SpringBoot实现单文件上传功能,供大家参考,具体内容如下架构为springboot+thymeleaf,采用ajax方式提交1. 页
- 一、背景项目中新建module之后,要在该目录下新增java Class文件,右键——》New发现无Java Class选项。二、办法Fil
- /* * 获取当前的手机号 &nb
- 一:什么是协变与逆变协变指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型,逆变指能够使用比原始指定的派生类型的派生程度更小(不
- 题目要求:两人比赛,A,B,每人最开始分得6张手牌,手牌大小为从1到9 A先出牌,B后出牌,若出牌在桌面上存在,在出牌人获得两张相同牌中间的
- 如果对一个值可以包含多个,那么可以使用枚举,加上Flags。新建一个Flags枚举类型:[Flags] publi
- 本文实例讲述了Java编程实现获取当前代码行行号的方法。分享给大家供大家参考,具体如下:最近的项目中,为了实现自定义的log类,能够输出具体
- 今天在一个 .NET Core 项目中调用一个自己实现的使用 params 可变参数的方法时触发了 null 引用异常,原以为是方法中没有对
- 选取单个元素直觉来说选取单个元素肯定会比选取多个要简单得多,不过这里也存在一些问题。我们先看下一般的做法的问题是什么,然后再看下如何用lam