【C#Unity题】1.委托和事件在使用上的区别是什么?2.C#中 == 和 Equals 的区别是什么?

1.委托和事件在使用上的区别是什么?
委托和事件是C#中的重要概念,通俗来讲,委托是一个可以指向特定方法的指针,可以将委托分配给不同的脚本,使它们能够完成不同的任务。而事件则是一种使用委托实现的通知机制,它告诉委托需要执行任务了。因此,委托定义了任务,而事件则是通知委托执行任务的通知。在 Unity 中,通过使用委托和事件,可以实现诸如响应按钮点击,处理游戏碰撞等功能。

它们在使用上的不同:
定义:委托是一种类型,它可以引用方法。事件是一种基于委托的机制,允许在事件发生时通知多个对象。

用法:委托是一种低级机制,可以直接调用关联的方法。事件则是一种高级机制,它可以被订阅和取消订阅,并在事件发生时引发通知。

安全性:委托是一种不安全的机制,它允许直接访问关联的方法,这可能会导致错误。事件则是一种安全的机制,它只允许通过订阅和取消订阅来访问关联的方法,因此不存在安全风险。

总之,委托是C#中的一种低级机制,它可以直接调用关联的方法,但可能带来安全问题;事件则是一种高级机制,它是基于委托的,允许在事件发生时通知多个对象,并且更加安全。

开发过程中的使用的案例

定义了一个事件委托类型 PlayerHealthEventHandler,它用于表示事件处理方法。
Player 类定义了一个 OnPlayerHealthChanged 事件,它在玩家生命值发生改变时被触发。
GameManager 类订阅了玩家生命值变化事件,并定义了事件处理方法 PlayerHealthChanged,它在接收到事件通知时被调用。
在 Main 方法中,创建了一个 Player 和一个 GameManager 对象,并订阅了事件。随后,通过调用 player.ChangeHealth 方法,改变了玩家生命值,并通知了事件订阅者。

sing System;

// 定义事件委托类型
public delegate void PlayerHealthEventHandler(int health);

public class Player
{
    
    
    // 定义事件
    public event PlayerHealthEventHandler OnPlayerHealthChanged;

    private int health;

    // 当玩家生命值发生改变时,发布事件
    public void ChangeHealth(int value)
    {
    
    
        health += value;
        if (OnPlayerHealthChanged != null)
        {
    
    
            OnPlayerHealthChanged(health);
        }
    }
}

public class GameManager
{
    
    
    // 订阅事件
    public void SubscribeEvent(Player player)
    {
    
    
        player.OnPlayerHealthChanged += PlayerHealthChanged;
    }

    // 当接收到玩家生命值变化的通知时,触发事件处理方法
    private void PlayerHealthChanged(int health)
    {
    
    
        Console.WriteLine("Player health changed to " + health);
    }
}

class Program
{
    
    
    static void Main(string[] args)
    {
    
    
        Player player = new Player();
        GameManager gameManager = new GameManager();

        // 订阅事件
        gameManager.SubscribeEvent(player);

        // 改变玩家生命值,并通知事件订阅者
        player.ChangeHealth(10);
    }
}

2.请说说你认为C#中 == 和 Equals 的区别是什么?

C# 中的 == 和 Equals 在比较两个对象的值时有着不同的行为。

== 运算符比较的是两个对象的内存地址是否相同,即是否是同一个对象的引用。如果两个对象的引用相同,那么它们的内存地址也相同,此时 == 运算符的结果为 true。如果两个对象的引用不同,即使它们的值相同,== 运算符的结果仍然为 false。

Equals 方法是比较两个对象的值是否相等,它会比较对象的内容,而不是内存地址。默认情况下,Equals 方法是比较对象的引用是否相等,即是否是同一个对象。但是,许多 .NET 类都重写了 Equals 方法,使其在比较两个对象的内容时得到正确的结果。

如果要比较两个对象的值是否相等,应该使用 Equals 方法。

开发过程中的使用的案例

Equals 方法常常被用于比较游戏对象。

if (object1.Equals(object2))
    // The two objects are the same
else
    // The two objects are different

另一个使用场景是在对游戏对象进行分组,比如将相同类型的游戏对象分为一组。

List<GameObject> groupA = new List<GameObject>();
List<GameObject> groupB = new List<GameObject>();

foreach (var gameObject in allGameObjects)
{
    
    
    if (gameObject.GetType().Equals(typeof(TypeA)))
    {
    
    
        groupA.Add(gameObject);
    }
    else if (gameObject.GetType().Equals(typeof(TypeB)))
    {
    
    
        groupB.Add(gameObject);
    }
}

注意: == 运算符比较的是两个引用的内存地址,所以当两个对象实例是在不同的内存地址上创建的,即使它们的内容完全相同,它们也不相等。因此,在比较两个引用类型的对象时,通常使用 Equals 方法,因为它比较的是对象的内容,而不是内存地址。

class Person
{
    
    
    public string Name {
    
     get; set; }
    public int Age {
    
     get; set; }

    public override bool Equals(object obj)
    {
    
    
        if (obj == null) return false;
        if (!(obj is Person)) return false;
        Person person = (Person)obj;
        return Name == person.Name && Age == person.Age;
    }
}

void Example()
{
    
    
    Person person1 = new Person {
    
     Name = "ZhangSan", Age = 20 };
    Person person2 = new Person {
    
     Name = "ZhangSan", Age = 20 };
    Debug.Log(person1 == person2); // 输出"False"
    Debug.Log(person1.Equals(person2)); // 输出"True"
}

它们的内容完全相同,但是由于它们是在不同的内存地址上创建的,所以使用 == 运算符比较它们的结果为 False。但使用 Equals 方法比较它们时,结果为 True,因为我们在 Person 类的 Equals 方法中重写了对象的内容比较方式,比较了对象的姓名和年龄是否相同。

另外,使用 Equals 方法还有另一个优点是,如果没有重写 Equals 方法,则它会使用默认的对象内容比较方式,该方式与使用 == 运算符的比较方式相同。因此,即使没有重写 Equals 方法,也可以使用 Equals 方法进行对象内容比较。

总的来说,使用 Equals 方法比较对象的内容更灵活,更具灵活性,因此在 Unity 游戏开发中,使用 Equals 方法比较对象是非常常见的。

3.结构体(Struct)和类(Class)的区别

  1. 值类型 vs 引用类型:结构体是值类型(Value Type),类是引用类型(Reference
    Type)。这意味着结构体在赋值和传递参数时,是按值传递的,而类是按引用传递的。
  2. 内存分配:结构体在创建时,分配在栈上,而类则分配在堆上。这意味着,结构体的创建和销毁速度比类快,但是结构体内存占用较大时会带来栈溢出的风险。
  3. 继承:类支持继承和多态,而结构体不支持继承,也不能声明虚函数。
  4. 默认构造函数:结构体可以使用默认构造函数,而类必须手动声明一个构造函数。
  5. 默认值:结构体可以有默认值,而类没有默认值,需要手动赋值或者使用构造函数初始化。

在游戏开发中,结构体通常用来表示游戏中的简单数据类型,如向量坐标、颜色、边界框等。而使用类来表示游戏对象、组件等复杂的对象。但在某些情况下,为了性能和代码清晰度的考虑,也可以使用结构体来表示复杂数据类型。
在这里插入图片描述
需要注意的是,表格中的内容并不是绝对的,也有些情况下会有例外。例如,结构体也可以通过实现接口来实现类似继承的效果,而类也可以使用值类型语义来实现类似值类型的行为。因此,在具体应用时,需要根据具体情况来选择使用结构体还是类。

4.基类(Base Class)和接口(Interface)的区别

在Unity中,基类(Base Class)和接口(Interface)是两种不同的代码结构。基类是一种类,而接口则是一种规范。下面是它们之间的区别:

继承关系:基类可以被继承,而接口不能被继承。
实现方式:类可以实现多个接口,但只能继承一个基类。
成员方法:基类可以提供实现,子类可以选择重写或者继承。接口只提供方法声明,需要实现类去实现。
访问权限:基类中的成员可以被子类访问,接口中的成员必须是公共的。
关系:基类和子类的关系是 is-a,即子类是基类的一种。而实现接口的类和接口之间的关系是 has-a,即类具有接口的某些特征。在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_18809975/article/details/128957760
今日推荐