unity学习笔记-C#泛型

什么是泛型

泛型(Generic) 允许您延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。换句话说,泛型允许您编写一个可以与任何数据类型一起工作的类或方法。

为什么要用泛型

它有助于您最大限度地重用代码、保护类型的安全以及提高性能
您可以创建泛型集合类。.NET 框架类库在 System.Collections.Generic 命名空间中包含了一些新的泛型集合类。您可以使用这些泛型集合类来替代 System.Collections 中的集合类。
您可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
您可以对泛型类进行约束以访问特定数据类型的方法。
关于泛型数据类型中使用的类型的信息可在运行时通过使用反射获取。

泛型的使用

  • 泛型类
    原始写法
public class NewBehaviourScript : MonoBehaviour  
{  
    // Use this for initialization  
    void Start()  
    {  
        Water test = new Water();  
        test.name = "KuangQuanShui";  
        test.temperature = 100;  
        Debug.Log("水的名字: " + test.name + "   水的温度: " + test.temperature);  
    }  
}  
public struct Water  
{  
    public string name;//水的名字  
    public int temperature;//水的温度  
} 

使用泛型写法

using System;
using System.Collections.Generic;

public class fanxing : MonoBehaviour  
{  
    // Use this for initialization  
    void Start()  
    {  
        Water<string> test1 = new Water<string>();  
        test1.info = "KuangQuanShui";//在此传入水的名字是"矿泉水"(可以将"T"看作是string类型)  
  
        Water<int> test2 = new Water<int>();  
        test2.info = 100;//在此传入水的温度是 100(可以将"T"看作是int类型)  
        Debug.Log("水的名字: " + test1.info + "   水的温度: " + test2.info);  
    }  
}  
public class Water<T>  
{  
    public T info;//水的信息(属性)  
}  
  • 泛型方法
using System;
using System.Collections.Generic;

//泛型方法
//unity3D中用的最多的泛型方法应该是GetCompent<T>
//T就是占位符,当调用这个方法的你要告诉编译器,这个T的具体类型。
//另外,"T"只是一个标识,完全可以用其他代替,如"K","MyType"等,只是使用习惯。
//比如:
GameObject player;
Animator animator;
void Start()
    {
		//在场景中找到名为MyPlayer物体
		player = GameObject.Find("MyPlayer");
		//获取该物体上的Animator组件
		animator = player.GetComponent<Animator>();
		//对于使用AddComponent<T>()、GetCompent<T>()这两个泛型方法来说,需要了解的就是:T就是你想要的具体的组件类型。
		//对于泛型方法来说,泛型的作用就是占位和约束的作用。
    }       
	//下面来说声明泛型函数
    /// <summary>
    /// 比较等级;
    /// </summary>
    /// <returns>
    /// 若t1>=t2的等级,则返回true;否则返回false
    /// </returns>
    /// where T : IRole where K : IRole的作用是约束传入的两个参数类型必须要实现IRole这个接口;
    /// 这样就定义好了一个泛型方法
    public bool CompareLevel<T,K>(T t1,    K t2) where T : IRole where K : IRole
    {
        //因为泛型t1,t2都被约束需要实现接口,所以我们可以强制转换到IRole来获取level比较
        return ((IRole)t1).level >= ((IRole)t2).level;
    }
    //那么怎么使用呢?
    //接下来看:
    public void Test()
    {
        //先定义三个测试用的类型
        MyNPC npc =new MyNPC();
        MyPlayer player =new MyPlayer();
        MyMonster monster =new MyMonster();
        //对各个类型的level赋值
        npc.level =1;
        player.level =2;
        monster.level =3;
        //比较npc和player的level就很简单了,只需要这样调用即可
        bool b1 = CompareLevel<MyNPC,MyPlayer>(npc,player); //npc?payer//false                    
        bool b2 = CompareLevel<MyNPC,MyMonster>(npc,monster);//npc?monster//false
        bool b3 = CompareLevel<MyPlayer,MyMonster>(player,monster);//payer?monster//false
    }
    
    public interface IRole 
    {
        int level{get;set;}
    }
    public class MyPlayer:IRole
    {
        public int level{get;set;}
    }
    public class MyNPC:IRole
    {
        public int level{get;set;}
    }
    public class MyMonster:IRole
    {
        public int level{get;set;}
    }
  • 泛型委托
    无返回值 的泛型委托,可以有0~16个参数(函数重载)
using System;
using System.Collections.Generic;

public delegate void Action();                               // 无参数
public delegate void Action<in T>(T obj);                    // 1个参数
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2); // 2个参数
// ...... 最多16个参数

// 使用举例
    Action action0 = () => { };
    Action<int> action1 = (a) => { };
    Action<int, float> action2 = (a, b) => { };
    Action<int, int, double> action2 = (a, b, c) => { };
    // ......

有返回值 的泛型委托,可以有0~16个参数(不包括返回值类型) (函数重载)

public delegate TResult Func<out TResult>(); // 无参数
public delegate TResult Func<in T, out TResult>(T arg); // 1个参数
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2); // 2个参数
// ...... 最多16个参数(不包括TResult)

// 使用举例
    Func<int> func0 = () => { return 0; };
    Func<int, int> func1 = (a) => { return a; };
    Func<int, int, int> func2 = (a, b) => { return a + b; };
    // ......

*返回值为bool 的泛型委托,只能传递1个参数其实相当于 TResult Func<in T, out TResult>(T arg); 的 TResult为bool *

// 只有一个泛型委托,没有多参数重载
public delegate bool Predicate<in T>(T obj);

// 使用举例
    Predicate<int> p = (a) => { return a > 0; };
  • 泛型约束
public class fanxing : MonoBehaviour  
{  
    // Use this for initialization  
    void Start()  
    {  
        WaterBase waterInfo = new WaterBase();  
        Water<WaterBase> test3 = new Water<WaterBase>();//Water<限定只能为WaterBase类型>  可以将"T"看作是WaterBase类型  
        test3.info = waterInfo;  
        test3.info.name = "KuangQuanShui";  
        test3.info.temperature = 100;  
        Debug.Log("水的名字是: " + test3.info.name + "   水的温度是: " + test3.info.temperature);  
    }  
}  
public class Water<T> where T : WaterBase  
{  
    public T info;//水的信息(属性) 可看作"T"的类型是WaterBase  
}  
public class WaterBase  
{  
    public string name;  
    public int temperature;  
}  

如果是多个占位符的泛型(两个),示例代码如下:

public class fanxing : MonoBehaviour  
{  
    // Use this for initialization  
    void Start()  
    {  
        //从A产线出来的生产日期是string类型的"20130610",水是矿泉水,温度是20,  
        Water<string, WaterBase> test1 = new Water<string, WaterBase>();//Water<任意类型,直接收WaterBase类型> 在此"T"相当于string类型  
        test1.data = "20130610";  
        test1.info.name = "KuangQuanShui";  
        test1.info.temperature = 20;  
        //从B产线出来的生产日期是int类型的20130610,水是纯净水,温度是20,  
        Water<int, WaterBase> test2 = new Water<int, WaterBase>();//Water<任意类型,直接收WaterBase类型> 在此"T"相当于int类型  
        test2.data = 20130610;  
        test2.info.name = "ChunJingShui";  
        test2.info.temperature = 20;  
    }  
}  
public class Water<T, U> where U : WaterBase //限定"U"只能接收WaterBase类型  
{  
    public T data;//出厂日期(可接受int型的20130610,或者string类型的"20130610");  
    public U info;//水的具体信息(矿泉水/纯净水...温度)  
}  
public class WaterBase  
{  
    public string name;  
    public int temperature;  
}  
  • 泛型接口

  • 泛型单例的使用

using System;
using UnityEngine;

public class SingletonProvider<T> where T : class ,new()
{
    private SingletonProvider()
    {
    }

    private static T _instance;
    // 用于lock块的对象
    private static readonly object _synclock = new object();

    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_synclock)
                {
                    if (_instance == null)
                    {
                        // 若T class具有私有构造函数,那么则无法使用SingletonProvider<T>来实例化new T();
                        _instance = new T();
                        //测试用,如果T类型创建了实例,则输出它的类型名称
                        Debug.Log("{0}:创建了单例对象" + typeof(T).Name);
                    }
                }
            }
            return _instance;
        }
        set { _instance = value; }
    }
}

public class NetIO 
{

    public static NetIO GetInstance()
    {
        return SingletonProvider<NetIO>.Instance;
    }

    public NetIO()
    {
        this.NetIoCreateTime = DateTime.Now;
    }

    public DateTime NetIoCreateTime
    {
        get { return _ct; }
        set { _ct = value; }
    }

    private DateTime _ct;
}

public void Update()
{
    Debug.Log(NetIO.GetInstance().NetIoCreateTime);
}

抽象类继承单例

using UnityEngine;

public abstract class SingletonBase<T> : MonoBehaviour
    where T : MonoBehaviour
{
    private static T _instance;

    public static T GetInstance()
    {
        if (_instance == null)
        {
            Debug.Log("Create " + typeof(T).ToString() + " singleton...");
            _instance = GameObject.FindObjectOfType<T>();
            if (_instance == null)
                Debug.LogError("Class of " + typeof(T).ToString() + " not found!");
        }
        return _instance;
    }
}

public class SingletonClass1 : SingletonBase<SingletonClass1> {

    private SingletonClass1() { }
}

public class TestClass : MonoBehaviour {

    void Awake () 
    {
        SingletonClass1 s1 = SingletonClass1.GetInstance();
    }
}

泛型的深入理解

参考:https://www.cnblogs.com/shawnzxx/p/3509021.html
https://www.cnblogs.com/shahdza/p/12261784.html
https://www.cnblogs.com/liaoguipeng/p/5130144.html
https://blog.csdn.net/eazey_wj/article/details/61915575

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值