访问auto属性中的支持字段

时间:2009-03-15 22:38:35

标签: c# .net-3.5 c#-3.0 properties encapsulation

有没有办法访问属性的支持字段以进行验证,更改跟踪等?

以下是可能的吗?如果没有,是否计划在.NET 4 / C#4中使用它?

public string Name
{
    get;
    set
    {
        if (value != <Keyword>)
        {
            RaiseEvent();
        }
        <Keyword> = value;
    }
}

我遇到的主要问题是,使用自动属性不允许在具有明确支持字段的属性的验证等方面具有相同的灵活性。然而,显式支持字段在某些情况下具有缺点,即允许其所包含的类在访问和重用属性的验证,更改跟踪等时访问支持字段,就像可能正在访问的任何其他类一样外部的财产。

在上面的示例中,对支持字段的访问将限定为属性,从而防止绕过属性验证,更改跟踪等。

编辑:我已经更改了&lt;支持领域&gt;到&lt;关键字&gt;。我会提出一个类似于价值的新关键字。 字段会做得很好,虽然我确定它已经在很多现有代码中使用了。

6 个答案:

答案 0 :(得分:13)

不,没有。如果要访问支持字段,请不要使用自动属性并自行滚动。

我同意拥有一个只能由该属性访问而不是该类其他人才能访问的字段会很棒。我会一直使用它。

答案 1 :(得分:6)

正如MSDN所述:

  

“在C#3.0及更高版本中,自动实现   属性使属性声明   没有额外逻辑时更简洁   属性访问者需要。   它们还使客户端代码能够创建   对象将属性声明为   如下例所示,   编译器创建一个私有的,匿名的   只能访问支持字段   通过财产的获取和设置   存取器“。

由于您的访问者中有其他逻辑,因此在您的方案中使用自动实现的属性是不合适的。

虽然支持字段确实存在,但它会被赋予一个错误的名称以阻止您轻松引用它 - 这个想法是您从不直接引用该字段。为了利益起见,您可以使用Reflector来反汇编代码并发现字段名称,但我建议您不要直接使用该字段,因为此名称可能确实存在易变性,因此您的代码可能随时中断。

答案 2 :(得分:3)

在Mehrdad的回答中读到你的评论后,我想我更了解你的问题。

您似乎担心开发人员能够在他们正在编写的类中访问私有状态,绕过您的验证逻辑等。这表明该状态根本不应该包含在类中。

我会建议以下策略。编写表示ValidatedValue的泛型类。此类仅包含后备值,并且仅允许通过get和set方法进行访问/变异。委托被传递给ValidatedValue以表示验证逻辑:

public class ValidatedValue< T >
{
    private T m_val;
    public ValidationFn m_validationFn;

    public delegate bool ValidationFn( T fn );

    public ValidatedValue( ValidationFn validationFn )
    {
        m_validationFn = validationFn;
    }

    public T get()
    {
        return m_val;
    }

    public void set(T v)
    {
        if (m_validationFn(v))
        {
            m_val = v;
        }
    }
}

当然,您可以根据需要添加更多代表(例如,支持更改前/后通知)。

您的班级现在将使用ValidatedValue代替您的媒体资源的后备商店。

下面的示例显示了一个类MyClass,其中一个整数被验证为小于100.请注意,抛出异常的逻辑是在MyClass中,而不是ValidatedValue。这允许您执行依赖于MyClass中包含的其他状态的复杂验证规则。 Lambda表示法用于构造验证委托 - 您可以绑定到成员函数。

public partial class MyClass
{
    private ValidatedValue<int> m_foo;

    public MyClass()
    {
        m_foo = new ValidatedValue<int>(
            v => 
            {
                if (v >= 100) RaiseError();
                return true;
            }
        );
    }

    private void RaiseError()
    {
        // Put your logic here....
        throw new NotImplementedException();
    }

    public int Foo
    {
        get { return m_foo.get(); }
        set { m_foo.set(value); }
    }
}

希望有所帮助 - 有点偏离原始主题,但我认为它更符合您的实际问题。我们所做的是将验证逻辑从属性中移除并将其放在数据上,这正是您想要的位置。

答案 3 :(得分:2)

不,但你可以在子类中:

public class Base
{
    public string Name
    {
        get;
        virtual set;
    }
}

public class Subclass : Base
{
    // FIXME Unsure as to the exact syntax.
    public string Name
    {
        override set
        {
            if (value != base.Name)
            {
                RaiseEvent();
            }

            base.Name = value;
        }
    }
}

答案 4 :(得分:1)

如果您要这样做,为什么要使用自动属性?!

一个简单的属性已经在1.0中完成了。我不认为为每种特殊情况增加语言的复杂性是有意义的。您需要该属性来执行普通存储/检索模型或需要更多。在后一种情况下,正常的财产就可以了。

答案 5 :(得分:1)

我害怕你不能这样做。这是我开始编写MoXAML Power Toys的原因之一,它提供了将自动属性转换为Notify属性的功能。