我有两个继承自同一个抽象类的类。我希望他们两个或至少一个人知道另一个人的特定属性的变化。这样做有什么简单的方法吗?我一直在尝试将变量移动到父类,但是这只创建了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'。
答案 0 :(得分:5)
如果这是作为一个模拟,那么当狼在狩猎时不会告诉鹿,它必须找出答案。这里的模拟是有一些方法,鹿可以查询狼的存在(类似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
列表。
答案 1 :(得分: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
,在上面的示例中将详细信息写入控制台。
在您的用例中,您可以让事件在另一个类中调用一个方法(如果我理解正确的话)。
答案 2 :(得分: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);
}
}
答案 3 :(得分: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();
}
}
}
这可以改进为更通用,但它是将一个对象的引用传递给另一个对象的基本思想。
答案 4 :(得分: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);
}
}