通用属性中的属性更改通知

时间:2012-04-20 16:35:52

标签: c# reflection

重新提出问题。向下滚动查看原始

好吧,也许我应该给你全部的照片。我有很多类看起来像这样:

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
}

还有一些名为Transform,Mesh,Collider,Appearance等的类都是从Component派生而来的,除了上面描述的属性之外什么都没有。这里重要的是调用ComponentChangedEvent。一切都很完美,但我一直在寻找一种方法,我不必一次又一次地为每个属性重写相同的逻辑。

我看了here并且喜欢使用通用属性的想法。我想出的是这样的:

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

但我无法获得LinearVelocity来自的实例,也无法获得字符串的名称。所以我的问题是,如果所有这一切都可能......

但似乎我没有选择,只能按照我的方式继续这样做,手动为每个属性编写这个逻辑。

原始问题:

获取从属性声明类的实例

我有一个属性的类:

public class Foo
{
    public int Bar { get; set; }
}

在另一个背景下,我有这样的事情:

Foo fooInstance = new Foo();
DoSomething(fooInstance.Bar);

然后,在DoSomething中我需要让fooInstance除了parameter之外什么都没有。从上下文来看,可以假设不会将任何整数传递到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上使用反射或自定义属性?

4 个答案:

答案 0 :(得分:3)

为什么你只想向DoSomething发送一个属性,将它发送给整个对象:),所以它会变成,

DoSomething(fooInstance);

然后,您的函数将接受对象而不是参数。您可以使用此函数的重载来确保旧代码不会中断。

答案 1 :(得分:2)

有几种方法可以解决实施INotifyPropertyChanged的问题。除了没有实现接口并以不同的方式引发事件之外,你几乎都在做同样的事情。但是所有的解决方案也适用于你。

  1. 与您一样,使用字符串参数调用方法:OnPropertyChanged("Property")
  2. 使用lambda调用方法,该lambda使用属性:OnPropertyChanged(() => Property)。这样做的好处是可以在编译时检查拼写错误和重构友好。
  3. 使用caller information注入属性名称:OnPropertyChanged()。这将在C#5中有效。
  4. 使用类似Castle DynamicProxy的东西在运行时创建一个派生类,它将为您调用该方法。这意味着您需要创建属性virtual,并且只需要通过Castle创建类的实例。
  5. 使用AOP框架在编译后修改属性的代码以调用方法。

答案 2 :(得分:0)

无法从fooInstance获取parameterparameter按值传递,并且只是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
}

答案 3 :(得分:0)

属性只是一个字段,它返回对堆上某个对象的引用(即其地址)。如果property不是引用类型,则返回object的值。

所以,当你做类似的事情时

DoSomething(fooInstance.Bar);

您只需将对象Bar的地址传递给方法。

如果Bar是引用类型(即类)。想象一下,Mr.Foo有一个Mr.Bar的地址( 462 for Marion County,Indiana )。 CLR夫人向Mr.Foo询问Mr.Bar的地址。然后将此地址告诉需要Mr.Bar地址的人。怎么会有人知道,CLR问Foo有关Bar的地址?他只为印第安纳州马里恩县收到了 462的地址

如果是值对象(int,double,structs等),Mr.Foo有一个名为Bar的酷mp3曲目。 CLR夫人创建了该mp3音轨的副本并将其发送给某人。怎么会有人知道,他的mp3轨道栏是Mr.Foo的轨道的副本?

所以,如果你想让某人了解Mr.Foo,你需要将Mr.Foo的地址传递给他:

DoSomething(fooInstance);

有了这个地址,有人可以访问Mr.Foo并向他询问Mr.Bar的地址,或者创建他的mp3轨道的副本:)