通用属性中的属性更改通知
本文关键字:属性 通知 | 更新日期: 2023-09-27 18:31:51
改写了这个问题。向下滚动查看原件
好吧,也许我应该给你全貌。我有很多类看起来像这样:
public class Movement : Component
{
private Vector3 linearVelocity;
public Vector3 LinearVelocity
{
get
{
return linearVelocity;
}
set
{
if (value != linearVelocity)
{
linearVelocity = value;
ComponentChangedEvent<Movement>.Invoke(this, "LinearVelocity");
}
}
}
// other properties (e.g. AngularVelocity), which are declared exactly
// the same way as above
}
还有称为变换、网格、碰撞体、外观等的类,它们都派生自Component
,并且都只有如上所述声明的属性。这里重要的是调用ComponentChangedEvent
。一切都很完美,但我正在寻找一种方法,让我不必一次又一次地为每个属性重写相同的逻辑。
我在这里看了一下,喜欢使用泛型属性的想法。我想出的看起来像这样:
public class ComponentProperty<TValue, TOwner>
{
private TValue _value;
public TValue Value
{
get
{
return _value;
}
set
{
if (!EqualityComparer<TValue>.Default.Equals(_value, value))
{
_value = value;
ComponentChangedEvent<TOwner>.Invoke(
/*get instance of the class which declares value (e.g. Movement instance)*/,
/*get name of property where value comes from (e.g. "LinearVelocity") */);
}
}
}
public static implicit operator TValue(ComponentProperty<TValue, TOwner> value)
{
return value.Value;
}
public static implicit operator ComponentProperty<TValue, TOwner>(TValue value)
{
return new ComponentProperty<TValue, TOwner> { Value = value };
}
}
然后我会像这样使用它:
public class Movement : Component
{
public ComponentProperty<Vector3, Movement> LinearVelocity { get; set; }
public ComponentProperty<Vector3, Movement> AngularVelocity { get; set; }
}
但是我无法获得线性速度的来源实例,也无法将其名称命名为字符串。所以我的问题是,如果这一切都有可能......
但似乎我别无选择,只能继续按照我的方式做,手动为每个属性编写此逻辑。
原始问题:
从属性获取声明类的实例
我有一个带有属性的类:
public class Foo
{
public int Bar { get; set; }
}
在另一种情况下,我有这样的东西:
Foo fooInstance = new Foo();
DoSomething(fooInstance.Bar);
然后,在DoSomething
我需要从只有parameter
中得到fooInstance
.从上下文中,假设不是任何整数被传递到DoSomething
,而只是整数的公共属性。
public void DoSomething(int parameter)
{
// need to use fooInstance here as well,
// and no, it is not possible to just pass it in as another parameter
}
这可能吗?使用反射,或者可能是属性上的自定义属性Bar
?
为什么你只想将一个属性发送到 DoSomething,将整个对象:)发送给它,这样它就会变成,
DoSomething(fooInstance);
然后,您的函数将接受对象而不是参数。可以使用此函数的重载来确保旧代码不会中断。
有几种方法可以处理实现INotifyPropertyChanged
。你正在做几乎相同的事情,只是你没有实现接口并以不同的方式引发事件。但所有解决方案也都适用于您。
- 像你一样,调用一个带有字符串参数的方法:
OnPropertyChanged("Property")
。 - 使用使用该属性的 lambda 调用方法:
OnPropertyChanged(() => Property)
。这样做的好处是,它可以在编译时检查拼写错误和重构友好。 - 使用调用方信息注入属性的名称:
OnPropertyChanged()
。这将在 C# 5 中工作。 - 使用类似 Castle DynamicProxy 的东西在运行时创建一个派生类,该类将为您调用该方法。这意味着你需要使你的属性
virtual
,并且你只需要通过 Castle 创建类的实例。 - 编译后使用 AOP 框架修改属性的代码以调用该方法。
办法从parameter
获得fooInstance
。 parameter
是按值传递的,只是fooInstance.Bar
值的副本,它不再与fooInstance
话虽如此,显而易见的解决方案是像这样写DoSomething
public void DoSomething(Foo parameter)
{
// need to use fooInstance here as well,
// and no, it is not possible to just pass it in as another parameter
}
只是一个字段,它返回对堆上某个对象的引用(即其地址)。如果属性不是引用类型,则返回对象的值。
所以,当你做类似的事情
DoSomething(fooInstance.Bar);
您只需将对象 Bar 的地址传递给方法即可。
如果 Bar 是引用类型(即 .class)。想象一下,Foo 先生的地址是 Mr.Bar(印第安纳州马里恩县为 462)。CLR太太向符先生询问 Mr.Bar 的地址。然后将这个地址告诉需要 Mr.Bar 地址的人。怎么会有人知道,CLR问Foo关于Bar的地址?他只收到了印第安纳州马里恩县的地址462。
对于值对象(int,double,structs等),Mr.Foo有一个名为Bar的很酷的mp3曲目。怎么会有人知道,他的mp3曲目Bar是Foo先生曲目的副本?
所以,如果你想让别人知道Foo先生,你需要把Mr.Foo的地址传递给他:
DoSomething(fooInstance);
有了这个地址,有人可以访问Foo先生并询问他 Mr.Bar 的地址,或者创建他的mp3曲目的副本:)