繁体   English   中英

如何使C#类相互了解?

[英]How to make c# classes aware of each other?

我有两个从同一个抽象类继承的类。 我希望他们两个或至少一个知道另一个属性的变化。 有没有简单的方法可以做到这一点? 我一直试图将变量移至父类,但这仅创建了2个相同的变量,当我在第一个变量中创建对另一个类的引用时,会发生相同的事情。 谢谢。

这是我的代码如下所示:

public abstract class Animal
    {
        public int MovementSpeed;
        public bool Death;
        public string Feedback;

        public bool DeerCaught;
        public int tiredRate;
        public virtual int Movement()
        {
            MovementSpeed = MovementSpeed - tiredRate;
            return MovementSpeed;
        }

        public virtual string Print()
        {
            return Feedback;
        }
    }

    public class Deer : Animal
    {
        public string hidden;
        public string Foraging;

        public int DeerCount;


        public Deer()
        {
            this.DeerCount = 10;
            this.DeerCaught = false;
            this.MovementSpeed = 10;
            this.tiredRate = 2;

        }
        public void Hide()
        {
            if (Hunting)
            {
                Feedback = "The deer is hiding.";
                if (DeerCount > 0)
                {
                    Print(); 
                }

            }
            else
            {
                //Forage();
            }
        }
        public void Forage()
        {
            if (!Hunting)
            {
                Feedback = "The deer is searching for food.";
                if (DeerCount > 0)
                {
                    Print();
                }

            }
            else
            {
                //Hide();
            }
        }
    }

    public class Wolf : Animal
    {

        public int Hunger;
        public bool Hunting;
        public Wolf()
        {
            this.Hunting = false;
            this.Hunger = 10;
            this.MovementSpeed = 10;
            this.tiredRate = 1;
        }
        public bool Hunt()
        {
            if (Hunger < 5)
            {
                Hunting = true;
                Feedback = "The wolf is searching for his next meal.";
                if (DeerCaught == true)
                {
                    Hunger++;
                }
                else
                {
                    Hunger--;
                }
                return Hunting;
            }
            else
            {
                Hunting = false;
                Feedback = "The wolf decides to rest.";
                Hunger--;
                return Hunting;
            }
        }
        public void Die()
        {
            if (Hunger < 0)
            {
                Death = true;
                Feedback = "The wolf has lost the hunt.";
            }

        }

    }

我尝试在基类中将Hunting设置为静态,但是当我运行每个类的方法时,最终得到了两个不同版本的“ Hunting”。

如果将其用作模拟,则不会告诉Deer狼何时狩猎,它必须找出来。 这里的类似物是通过某种方式让鹿可以查询狼的存在(例如Deer.LookForWolves() ,然后检查每只狼的Hunting属性的值。这将需要某种控制器类,代表世界。

class World
{
    public static List<Animal> Animals = new List<Animal>();
    //...
}

class Deer : Animal
{
    //...

    bool IsSafe()
    {
        return LookForWolves().All(wolf => !wolf.Hunting);
    }

    List<Wolf> LookForWolves()
    {
        return World.Animals.OfType<Wolf>();
    }

    //...

另外,您可以将World视为每个Animal的成员,并通过构造函数传入。 取决于您,取决于您是否需要多个World对象,每个对象都有不同的Animal列表。

实现INotifyPropertyChanged可以帮助您:

首先,声明一些实现INotifyPropertyChanged类:

abstract class Base {

}

class ClassA : Base, INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    private string _property;
    public string ClassAProperty {
        get {
            return _property;
        }
        set {
            _property = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ClassAProperty"));
        }
    }
}

class ClassB : Base, INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    private string _property;
    public string ClassBProperty {
        get {
            return _property;
        }
        set {
            _property = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ClassBProperty"));
        }
    }
}

然后,连接新实例以订阅PropertyChanged事件:

using System.ComponentModel;

static void Main(string[] args) {
    ClassA a = new ClassA();
    a.PropertyChanged += PropertyChanged;
    a.ClassAProperty = "Default value";

    ClassB b = new ClassB();
    b.PropertyChanged += PropertyChanged;
    b.ClassBProperty = "Default value";

    b.ClassBProperty = "new value in B";
    a.ClassAProperty = "new value in A";

    Console.Read();
}

static void PropertyChanged(object sender, PropertyChangedEventArgs e) {
    Console.WriteLine("Property {0} on object {1} was changed, the value is \"{2}\"", e.PropertyName, sender.GetType().Name, sender.GetType().GetProperty(e.PropertyName).GetValue(sender));
}

输出为:

Property ClassAProperty on object ClassA was changed, the value is "Default value"
Property ClassBProperty on object ClassB was changed, the value is "Default value"
Property ClassBProperty on object ClassB was changed, the value is "new value in B"
Property ClassAProperty on object ClassA was changed, the value is "new value in A"

每次设置任何一个属性时,都会调用PropertyChanged ,在上面的示例中,该PropertyChanged将详细信息写入控制台。

在您的用例中,您将让事件在另一个类中调用一个方法(如果我理解正确的话)。

一种非常基本的通知属性的方法,该属性使用您自己的委托定义进行了更改。 由于您不提供任何代码,因此我自己创建了一些类。 使用此示例修改您自己的代码:

public delegate void PropertyChangedEventHandler();

public abstract class Base
{
}

public class A : Base
{
    public event PropertyChangedEventHandler PropertyChanged;

    private int _value;
    public int Value
    {
        get { return _value; }
        set 
        { 
            _value = value;
            if (PropertyChanged != null)
            {
                PropertyChanged();
        }
    }
}

public class B : Base
{
    private A _a;

    public B(A a)
    {
        _a = a;
        a.PropertyChanged += new PropertyChangedEventHandler(a_PropertyChanged);
    }

    private void  a_PropertyChanged()
    {
        Console.WriteLine(_a.Value);
    }
}

public class Application()
{
    public void DoStuff()
    {
        var a = new A();
        var b = new B(a);
    }
}

基本思想是将一个对象的引用传递给另一个对象。 例如,告诉鹿它正在被狼猎杀:

public class Wolf : Animal
{
    public void Hunt(Deer deer)
    {
        deer.SetHunter(this);
    }
}

现在,鹿可以检查狼是否在猎杀它:

public class Deer : Animal
{
    Wolf _hunter;
    public void SetHunter(Wolf wolf)
    {
        _hunter = wolf;
    }

    public void Hide()
    {
        if (_hunter != null)
        {
            Feedback = "The deer is hiding.";
        }
        else
        {
            //Forage();
        }
    }
}

可以改进它以使其更通用,但这是将一个对象的引用传递给另一个对象的基本思想。

不要将公共字段用作类的属性。 这样,您将永远不会知道更改,因此无法通知其他人。 将公共字段放入属性中,并始终使用这些属性来更改值,即使是在Animal类内部也是如此。 然后可以使用属性设置器将更改通知其他人。

public abstract class Animal
{
    private int _movementSpeed;

    public int MovementSpeed
    {
        get
        {
            return _movementSpeed;
        }
        set
        {
            if (_movementSpeed != value)
            {
                _movementSpeed = value;
                OnMovementSpeedChanged();
            }
        }
    }

    protected virtual void OnMovementSpeedChanged()
    {
        // Derived classes can override this method.
        // It will be called each time MovementSpeed changes.
    }

    public virtual int Movement()
    {
        // always use the property to change the value
        // otherwise OnMovementSpeedChanged would never be called
        MovementSpeed -= tiredRate;
        return MovementSpeed;
    }
}

像已经提到的其他方法一样,您也可以在基类中实现INotifyPropertyChanged 由于这将事件用于通知,因此不仅派生类可以使用该事件,而且引用动物的任何其他对象也可以使用该事件。 方法基本相同。 每次属性值更改时,您都会调用一个触发事件的方法。 然后,任何其他对象都可以处理该事件。

public abstract class Animal : INotifyPropertyChanged
{
    private int _movementSpeed;

    public int MovementSpeed
    {
        get
        {
            return _movementSpeed;
        }
        set
        {
            if (_movementSpeed != value)
            {
                _movementSpeed = value;

                // call this method each time a property changes
                OnPropertyChanged(new PropertyChangedEventArgs("MovementSpeed"));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        // always implement events like this
        // -> check if the event handler is not null, then fire it
        if (PropertyChanged != null)
        {
            PropertyChanged(this, args);
        }
    }
}

想要处理事件的类可以这样做:

public class AnyClass
{
    public AnyClass(Animal anAnimal)
    {
        TheAnimal = anAnimal;
        anAnimal += Animal_PropertyChanged;
    }

    public Animal TheAnimal { get; private set; }

    private void Animal_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "MovementSpeed")
        {
            Console.WriteLine("MovementSpeed changed"); 
        }
    }
}

但是派生类不需要处理该事件。 由于OnPropertyChanged方法被声明为受保护的虚拟方法,因此它们可以覆盖它。

public class Deer : Animal
{
    protected override void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        if (args.PropertyName == "MovementSpeed")
        {
            Console.WriteLine("MovementSpeed changed");
        }

        // don't forget to call the base class otherwise the event will never get fired
        base.OnPropertyChanged(args);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM