[Unity] C#中级编程 - 04 - 泛型/构造函数/ref

[Unity中文课堂教程] C#中级编程 - 04 - 泛型/构造函数/ref

原教程视频地址:

《[Unity中文课堂教程预告片] C#中级编程_哔哩哔哩_bilibili》

《C#中级编程 - Unity中文课堂 (u3d.cn)》

《C# 泛型(Generic) | 菜鸟教程 (runoob.com)》

《C# 泛型讲解_泛型基础_C# Generic_天马3798-CSDN博客_c#泛型》

内容短小精悍简练,每节只有几分钟。很适合用来预习和复习。

类的构造函数

《C# 类(Class) | 菜鸟教程 (runoob.com)》(构造函数)先补充这个概念,和python的形式不太一样,之前没用到所以忘记了

  • 类的 构造函数 是类的一个特殊的成员函数,当创建类的新对象时执行。
  • 构造函数的名称与类的名称完全相同,它没有任何返回类型。

脚本①

public class Exercise_4_7 : MonoBehaviour
{
	int num = 0;
	static int num_s = 0;
	
    public Exercise_4_7()	// 构造函数,无须设返回类型,与类名相同
	{
		num_s += 1;
		num += 1;
		Debug.Log("创建了类对象,调用了构造函数");
	}
	
	public int num_get()	// 返回局部属性
	{
		return num;
	}
	
	public int nums_get()	// 返回静止属性
	{
		return num_s;
	}
}

脚本②

public class Exercise_4_8 : MonoBehaviour
{
    void Start()
    {
		Exercise_4_7 myClass = gameObject.AddComponent<Exercise_4_7>();
		Exercise_4_7 myClass_0 = gameObject.AddComponent<Exercise_4_7>();
		
		Debug.Log("num = " + myClass.num_get());		// 局部属性不通用
		Debug.Log("nums = " + myClass.nums_get());		// 静止属性通用
		// 二者均在创建对象时在构造函数中累加了
    }
}

ref:按引用传递参数

《ref 关键字 - C# 参考 | Microsoft Docs》菜鸟教程例子中看到了,补充一下。

  • 理解为传递指针,传递参数本身,而不是传递参数的值。也就说在内部修改形参就会直接影响修改了实参。
void Method(ref int refArgument)	// 若要使用 ref 参数,方法定义和调用方法均必须显式使用 ref 关键字
{
    refArgument = refArgument + 44;
}

int number = 1;			// 传递到 ref 或 in 形参的实参必须先经过初始化,然后才能传递。
Method(ref number);		// 显式使用关键字
Console.WriteLine(number);
// Output: 45
  • 在c#中还要其他方法参数关键字,如paramsinout。这些之后再详述吧。

泛型方法/类

  • 传参前,一般需要先规定类型,然后函数内就可对该类型作出针对的操作运算。而c#允许连同类型也设为一个参数,在调用时再设定。这种操作称为泛型。
  • 因为类型不确定,所以泛型不能作大部分操作运算,比如加减乘除、方法调用等,会在编译时就报错。基本上常用的是一些赋值或删除空对象的操作。

脚本①

public class Exercise_4_7 : MonoBehaviour
{
	public void Swap<T>(ref T num_0, ref T num_1)
	{
		T num_3;			// 创建临时变量,用于交互2个参数的值
		num_3 = num_0;
		num_0 = num_1;
		num_1 = num_3;
		// num_1 ++;		//	尝试是否可以作针对操作,不可用,会直接报错
		Debug.Log("使用泛型方法交互了 "+num_0+" 和 "+num_1+" 的内容");
	}
}

脚本②

public class Exercise_4_8 : MonoBehaviour
{
    void Start()
    {
		Exercise_4_7 myClass = gameObject.AddComponent<Exercise_4_7>(); //其实这就是泛型类
		
		int num_0 = 1,num_1 = 2;
		myClass.Swap<int>(ref num_0, ref num_1);	// 调用普通类中的泛型方法
    }
}
  • 一般为了方便调用,应该将该泛型方法设为静态。这就可省去创建对象一步了。
  • 泛型除了创建方法或类外,还能创建泛型接口泛型事件泛型委托,这里暂不细说。

泛型约束

  • 在声明泛型方法泛型类的时候,可以给泛型加上一定的约束来满足我们特定的一些条件。
public class CacheHelper<T> where T:new()
{
}
  • 使用关键字where。 下面列出了6中类型的约束

    1. where T: struct
      类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。有关更多信息,请参见使用可以为 null 的类型(C# 编程指南)。
    2. where T : class
      类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
    3. where T:new()
      类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
    4. where T:<基类名>
      类型参数必须是指定的基类或派生自指定的基类。
    5. where T:<接口名称>
      类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
    6. where T:U
      为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。

    《C# 泛型讲解_泛型基础_C# Generic_天马3798-CSDN博客_c#泛型》

  • 泛型类和泛型方法差不多,在实例化时会需要在尖括号内输入类型。其实在unity中早有用过泛型类,比如上面例子中,实例化 “继承了MonoBehaviour的类” 时用到的方法。

应用例子

在之前学习麦扣的教程时,第一次接触到泛型的用法。当时看不懂其作用,现在再看,个人认为是打包创建静态类的过程。下面贴出全部代码,以示参考学习。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Singleton<T> : MonoBehaviour where T:Singleton<T>	// 约束只能是类,且只能是继承了该泛型类的类。
{
	private static T instance;
	
	public static T Instance			// 设置参数只可读,
	{
		get
		{
			return instance;
		}
	}
	
	// 实例化
	protected virtual void Awake()		// protected 关键字代表只能子类访问
	{									// virtual 关键字代表子类能复写该方法
		if (instance != null)
			Destroy(gameObject);		// 如果静态类存在就删除
		else							// 好奇这里是不是不应该有else,当时弹幕也疑惑。
			instance = (T)this;			// 从新获取静态类
	}
	
	// 判断是否已实例化
	public static bool IsInitialized	// 同上
	{
		get 
		{
			return instance != null;	// 使用get关键字的巧妙,函数都省略,直接写在这里。
		}
	}
	
	// 清空实例化
	protected virtual void OnDestroy()	// 关键字同上
	{
		if(instance == this)
		{
			instance = null;
		}
	}
}
  • 《C# virtual关键字详解 (biancheng.net)》《protected 关键字 - C# 参考 | Microsoft Docs》
  • 《C# 封装 | 菜鸟教程 (runoob.com)》(protected)

你可能感兴趣的:(#,unity,csharp,学习笔记,unity,c#,游戏引擎)