1

同じ抽象クラスから継承する2つのクラスがあります。私はそれらの両方または少なくとも一方が他方の特定のプロパティの変更を認識していることを望んでいます。これを行うための簡単な方法はありますか?変数を親クラスに移動しようとしましたが、同じ変数が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たが、各クラスのメソッドを実行すると、2つの異なるバージョンの「ハンティング」が発生します。

4

5 に答える 5

5

これがシミュレーションとして意図されている場合、Deer はオオカミが狩りをしていることを知らされず、見つけ出さなければなりません。ここでの類似点は、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>();
    }

    //...

または、コンストラクターを介して渡されたWorldeach のメンバーとして参照することもできます。それはあなた次第であり、それぞれが異なる のリストを持つ複数のオブジェクトAnimalが必要かどうかによって異なります。WorldAnimal

于 2013-03-01T11:11:24.603 に答える
2

実装のようなもの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が呼び出され、上記の例では詳細がコンソールに書き込まれます。

あなたのユースケースでは、イベントが他のクラスのメソッドを呼び出すようにします(私があなたを正しく理解していれば)。

于 2013-03-01T10:42:29.790 に答える
1

クラスのプロパティにパブリック フィールドを使用しないでください。この方法では、変更に気付かないため、他の人に通知することはできません。パブリック フィールドをプロパティに配置し、常にこれらのプロパティを使用して、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);
    }
}
于 2013-03-01T11:35:34.463 に答える
1

独自のデリゲート定義で変更されたプロパティを通知する非常に基本的な方法です。あなたはコードを提供していないので、私はいくつかのクラスを自分で作りました。これを例として使用して、独自のコードを変更します。

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);
    }
}
于 2013-03-01T10:47:29.953 に答える
1

基本的な考え方は、あるオブジェクトの参照を別のオブジェクトに渡すことです。たとえば、オオカミに狩られていることをシカに伝えます。

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();
        }
    }
}

これは、より汎用的になるように改善できますが、あるオブジェクトの参照を別のオブジェクトに渡すという基本的な考え方です。

于 2013-03-01T11:29:57.870 に答える