簡體   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