C#泛型和非泛型集合
泛型和非泛型集合
一、泛型
泛型是指不特定于某种数据类型。
通过在类型名称后的尖括号中指定类型参数来声明泛型,例如TypeName<T>,这里 T 是类型参数。
额外补充-属性
public int IntValue0 { get; set; } // 这句相当于以下段落
实例一(1):
public int IntValue0 { get; set; }
// 声明private整型IntValue1
private int IntValue1;
//方法赋予IntValue1数值(private修饰导致IntValue1访问仅在对象本身内部使用)
public void SetIntValue1(int value) { IntValue1 = value; }
// 使用(return IntValue1)获取IntValue1数值
public int GetIntValue1() { return IntValue1; }
实例一(2):
public void F1()
{
int b = IntValue0; // 使用属性get
IntValue0 = 10; // 使用属性set
int a = GetIntValue1(); // 使用方法get
SetIntValue1(10); // 使用方法set
}
/*
public int IntValue { get; set; }
这种写法是自动属性,自动生成他的get set功能。
是为了以后设计变更的时候 更容易扩展和修改
*/
// 常规写法
private float _FloatValue1;
public float FloatValue1
{
get // 这里相当于有个返回值
{
return _FloatValue1;
}
set // 这里相当于有个参数
{
_FloatValue1 = value;
}
}
// 属性的 get set 可以单独设置权限,默认public
// 但是只允许设置一边
public int IntValue3 { get; private set; }
实例一(3):使用属性示例
// 常见用法
private float _Hp; // 声明私有定义 _Hp
public float Hp // 声明公共浮点数 Hp
{
get // 获取_Hp数值为Hp值
{
return _Hp;
}
set // 赋值
{
_Hp = value; // 当Hp接受赋值时调用set(value值为外部赋值时的数值)
if (_Hp < 0) // 如果_Hp小于0
{
_Hp = 0; // 使_Hp等于0
}
}
}
public void Damage(int damage) // 定义一个方法Damage
{
Hp = Hp - damage; // Hp赋值为Hp减去传入的damege数值
}
1.泛型类
实例一(3):泛类型主要格式
// 单个类型泛型
class DataStore<T>
{
public T Data { get; set; }
}
// 多个类型的泛型类
class KeyValuePair<TKey, TValue>
{
public TKey Key { get; set; }
public TValue Value { get; set; }
}
2.泛型字段
泛型类可以包含泛型字段。但是无法初始化。
// 泛型字段
class DataStore<T>
{
public T data;
}
// 泛型数组
class DataStore<T>
{
public T[] data = new T[10];
}
3.泛型方法
实例一(4):泛型方法1
// 泛型方法使用
public class Sample :MonoBehaviour
{
public void Print3<T>(T value) //方法Print
{
Debug.Log($"这是一个{typeof(T).FullName}值,value = {value}");
}
// 泛型使用
Print3<int>(10); // 输出 "这是一个int值,10"
Print3<bool>(false); // 输出 "这是一个bool值,false"
}
实例一(5):泛型方法2
class DataStore<T>
{
private T[] _data = new T[10];
public void AddOrUpdate(int index, T item)
{
if(index >= 0 && index < 10)
_data[index] = item;
}
public T GetData(int index)
{
if(index >= 0 && index < 10)
return _data[index];
else
return default(T);
}
}
// 上面的 AddorUpdate() 和 GetData() 方法是泛型方法。
4.泛型约束
在声明泛型方法/泛型类的时候,可以给泛型加上一定的约束来满足我们特定的一些条件。
实例一(6):泛型约束
// 格式如下
// public void Print4<T>(T value) where T : new()
public void Print4<T>(T value)
where T : new()
//where T : struct // 只能是struct值类型
//where T : class // 只能是class类
//where T : new() // 必须有空构造函数
//where T : BaseClass // 基类约束
//where T : IInterface // 接口约束
//where T : U // 类型参数约束
{
}
// where T : struct 值类型约束
// T 只能是值类型
// 正确情况:
MyBox<int> box1 = new MyBox<int>();
MyBox<Vector3> box2 = new MyBox<Vector3>(); // Unity 常用结构体
// 错误情况:
//MyBox<string> box3 = new MyBox<string>(); // string 是引用类型
// where T : class 引用类型约束
// T 必须是引用类型(可以是null)
// 正确情况:
MyContainer<string> c1 = new MyContainer<string>();
MyContainer<List<int>> c2 = new MyContainer<List<int>>();
MyContainer<MyMonoBehaviour> c3 = new MyContainer<MyMonoBehaviour>();
// 错误情况:
//MyContainer<int> c4 = new MyContainer<int>(); // int 是值类型
// where T : new() 无参构造函数约束
// T 必须有一个公开且无参数的构造函数
//如果同时有多个约束,new() 必须放在最后。
//允许你在泛型类内部使用 new T() 创建实例。
public class Factory<T> where T : class, new()
// new() 在最后
{
public T CreateInstance()
{
return new T(); // 只有加了 new() 约束才能这样写
}
}
// 错误情况: new() 没有放在最后
// public class BadFactory<T> where T : new(), class { }
// where T : BaseClass 基类约束
// T 必须是指定的基类,或者派生自该基类
public class Enemy
{
public virtual void Attack()
{
}
}
public class Boss : Enemy
{
}
public class Army<T> where T : Enemy
{
public void StartAttack(T unit)
{
// 编译器知道 T 一定是 Enemy 或其子类,所以可以调用 Attack()
unit.Attack();
}
}
Army<Boss> bossArmy = new Army<Boss>();
// 错误情况:
Army<string> stringArmy = new Army<string>(); // 因为string 不继承自 Enemy
// where T : IInterface 接口约束
// T 必须实现指定的接口
public interface IDamageable
{
void TakeDamage(int amount);
}
public interface IHealable
{
void Heal(int amount);
}
// T 必须同时实现这两个接口
public class BattleUnit<T> where T : IDamageable, IHealable
{
public void Fight(T unit)
{
unit.TakeDamage(10);
unit.Heal(5);
}
}
// where T : U 裸类型约束/类型参数约束
// T 必须是 U,或者派生自 U。这里 U 是另一个类型参数
// T 必须派生自 U (或者 T 就是 U)
public class Pair<T, U> where T : U
{
public T Item1;
public U Item2;
public void Assign()
{
// 因为 T 是 U 的子类,所以 T 可以赋值给 U
Item2 = Item1;
}
}
//组合约束
//可以将上述约束组合使用,但必须遵守以下顺序规则:
//基类(如果有,必须是第一个,且只能有一个)。
//接口(可以有多个,任意顺序)。
//struct 或 class(通常放在接口之后,建议放在中间)。
//new()(必须是最后一个)。
// T 必须继承自 MonoBehaviour (基类)
// 并且实现 IComparable (接口)
// 并且有无参构造函数 (new())
public class MyComponent<T> where T : MonoBehaviour, IComparable, new()
{
}
二、泛型集合
1.列表
列表List <T>是强类型对象的集合,可以通过索引对其进行访问,并具有用于排序,搜索和修改列表的方法。
实例二:列表的主要结构与使用
// 列表
// 可以显式初始化
List<int> l = new() { 0, 1, 2, 3 };
List<int> list = new();
// 添加
list.Add(0);
list.Add(1);
// 修改
list[0] = 123;
// 删除下标
list.RemoveAt(0);
//删除所有元素
list.Clear();
//排序
list.Sort();
public int FSort(int x, int y) //详细见下方//排序详解
{
return -x.CompareTo(y);
}
// 遍历
foreach (int each in list) //foreach遍历
{
}
for (int i = 0; i < list.Count; i++) //for循环从0到Count计数
{
}
//排序详解
public class sample : MonoBehaviour //
public void F1()
{
List<int> list = new() { 2, 3, 1 };
list.Sort(); // 1, 2, 3
list.Sort(FSort); // 3, 2, 1 //使用FSort方法
list.Sort((x, y) => -x.CompareTo(y)); //等效上行内的方法
}
public int FSort(int x, int y) //FSort方法
{
return -x.CompareTo(y);
}
2.字典
字典的主要结构为Dictionary < TKey,TValue >它以不特定的顺序存储键值对
//字典可以显式初始化
Dictionary<string, int> d = new()
{
{"a", 1},
{"b", 2},
{"c", 3},
};
Dictionary<string, int> dict = new();
// 添加"a"与对应的数据
dict.Add("a", 1);
// 修改"a"对应的数据
dict["a"] = 1;
// 获取"a"对应的数据
int a = dict["a"];
// 尝试获取未知键"a"的值
if (dict.TryGetValue("a", out int b))
{
UnityEngine.Debug.Log(b);
}
// 查找是否含有未知键"a"
if (dict.ContainsKey("a"))
{
}
//删除字典中的元素
dict.Remove("a"); // 删除 "a"
//删除所有元素
dict.Clear();
三、非泛型集合
1.动态数组
ArrayList 是一个非泛型的对象集合,其大小会动态增加。它与Array相同,只是它的大小是动态增加的
//创建
var arlist = new ArrayList();
//添加元素
arlist1.Add(1);
arlist1.Add("Bill");
arlist1.Add(" ");
arlist1.Add(true);
arlist1.Add(4.5);
arlist1.Add(null);
//使用 AddRange (ICollection c)方法在 ArrayList 中添加一个完整的 Array
var arlist2 = new ArrayList()
{
1, "Bill", " ", true, 4.5, null
};
int[] arr = { 100, 200, 300, 400 };
arlist1.AddRange(arlist2); //在arraylist中添加arraylist
arlist1.AddRange(arr); //在arraylist中添加数组
//获取内容
//使用var关键字而不进行显式转换
var firstElement = arlist[0]; //返回1
var secondElement = arlist[1]; //返回"Bill"
//更新元素
arlist[0] = "Steve";
arlist[1] = 100;
// 遍历
foreach (int each in arlist) //foreach遍历
{
}
for (int i = 0; i < arlist.Count; i++) //for循环从0到Count计数
{
}
//在ArrayList中插入元素
arlist.Insert(1, "Second Item");
//删除内容
arList.Remove(null); //删除首次出现的null
arList.RemoveAt(4); //删除下标4处的元素
arList.RemoveRange(0, 2);//从第一个项目(下标为0)删除两个元素
C#泛型和非泛型集合
https://chooseqiu.com/posts/4cf0f5ba/