简体   繁体   English

在自动属性中访问支持字段

[英]Acessing the backing field in an auto property

Is there any way to access the backing field for a property in order to do validation, change tracking etc.? 有没有办法访问属性的支持字段,以便进行验证,更改跟踪等?

Is something like the following possible? 是否有类似以下内容? If not is there any plans to have it in .NET 4 / C# 4? 如果没有,是否有计划在.NET 4 / C#4中使用它?

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

The main issue I have is that using auto properties doesn't allow for the same flexibility in validation etc. that a property with a explicit backing field does. 我遇到的主要问题是使用自动属性不允许在具有明确支持字段的属性的验证等方面具有相同的灵活性。 However an explicit backing field has the disadvantage in some situations of allowing the class it is contained in to access the backing field when it should be accessing and reusing the validation, change tracking etc. of the property just like any other class that may be accessing the property externally. 然而,显式支持字段在某些情况下具有缺点,即允许其所包含的类在访问和重用属性的验证,更改跟踪等时访问支持字段,就像可能正在访问的任何其他类一样外部的财产。

In the example above access to the backing field would be scoped to the property thus preventing circumvention of the property validation, change tracking etc. 在上面的示例中,对支持字段的访问将限定为属性,从而防止绕过属性验证,更改跟踪等。

Edit: I've changed < Backing Field > to < Keyword >. 编辑:我已将<Backing Field>更改为<Keyword>。 I would propose a new keyword similar to value. 我会提出一个类似于价值的新关键字。 field would do nicely although I'm sure it's being used in a lot of existing code. 虽然我确信它在很多现有代码中被使用,但是字段会很好。

No there isn't. 不,没有。 If you want to access the backing field, then don't use auto properties and roll your own. 如果要访问支持字段,请不要使用自动属性并自行滚动。

I agree that it would be great to have a field that was only accessible by the property and not by the rest of the class. 我同意,拥有一个只能由财产而不是其他同类人员访问的字段会很棒。 I would use that all the time. 我会一直使用它。

As the MSDN states: 正如MSDN所述:

"In C# 3.0 and later, auto-implemented properties make property-declaration more concise when no additional logic is required in the property accessors. They also enable client code to create objects When you declare a property as shown in the following example, the compiler creates a private, anonymous backing field can only be accessed through the property's get and set accessors." “在C#3.0及更高版本中,当属性访问器中不需要额外的逻辑时,自动实现的属性使属性声明更简洁。它们还使客户端代码能够创建对象当您声明属性时,如以下示例所示,编译器创建一个私有的,匿名的后备字段只能通过属性的get和set访问器来访问。“

Since you have additional logic in you accessors, the use of auto-implemented properties is not appropriate in your scenario. 由于在访问器中有其他逻辑,因此在您的方案中使用自动实现的属性是不合适的。

While the backing field does exist, it is given a mangled name to stop you referencing it easily - the idea is that you never reference the field directly . 虽然支持字段确实存在,但它会被赋予一个错误的名称以阻止您轻松引用它 - 这个想法是您永远不会直接引用该字段 For interests sake, you can use Reflector to disassemble your code and discover the field name, but I would recommend you not use the field directly as this name may indeed be volatile, so your code could break at any time. 为了利益起见,您可以使用Reflector来反汇编代码并发现字段名称,但我建议您不要直接使用该字段,因为此名称可能确实存在易变性,因此您的代码可能随时中断。

Having read your comments in Mehrdad's answer, I think I understand your problem a bit better. 在Mehrdad的回答中阅读了你的评论后,我想我更了解你的问题。

It appears that you are concerned about the ability of the developer to access private state in the class they are writing, bypassing your validation logic, etc. This suggests that the state should not be contained in the class at all. 您似乎担心开发人员能够在他们正在编写的类中访问私有状态,绕过您的验证逻辑等。这表明该状态根本不应该包含在类中。

I would suggest the following strategy. 我会建议以下策略。 Write a generic class that represents a ValidatedValue. 编写表示ValidatedValue的泛型类。 This class holds only the backing value and only allows access/mutation via get and set methods. 此类仅包含后备值,并且仅允许通过get和set方法进行访问/变异。 A delegate is passed to the ValidatedValue to represent the validation logic: 委托被传递给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;
        }
    }
}

You could, of course, add more delegates as required (eg, to support pre/post change notification). 当然,您可以根据需要添加更多代理(例如,支持更改前/后通知)。

Your class would now use the ValidatedValue in place of a backing store for your property. 您的类现在将使用ValidatedValue代替您的属性的后备存储。

The example below shows a class, MyClass, with an integer that is validated to be less than 100. Note that the logic to throw an exception is in MyClass, not the ValidatedValue. 下面的示例显示了一个类MyClass,其中一个整数被验证为小于100.请注意,抛出异常的逻辑是在MyClass中,而不是ValidatedValue。 This allows you to do complex validation rules that depend on other state contained in MyClass. 这允许您执行依赖于MyClass中包含的其他状态的复杂验证规则。 Lambda notation was used to construct the validation delegate - you could have bound to a member function instead. 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); }
    }
}

Hope that helps - somewhat off the original topic, but I think it's more inline with your actual concerns. 希望有所帮助 - 有点偏离原始主题,但我认为它更符合您的实际问题。 What we have done is taken the validation logic away from the property and put it on the data, which is exactly where you wanted it. 我们所做的是将验证逻辑从属性中移除并将其放在数据上,这正是您想要的位置。

No, but you can in a subclass: 不,但你可以在一个子类中:

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

If you're gonna do so, why you are using auto properties?! 如果您要这样做,为什么要使用汽车房产?!

A simple property has done it way back in 1.0. 一个简单的属性已经在1.0中完成了。 I don't think it makes sense to add complexity to the language for every special case. 我不认为为每种特殊情况增加语言的复杂性是有意义的。 You either need the property to do plain store/retrieve model or need more than that. 您需要该属性来执行普通存储/检索模型或需要更多。 In the latter case, a normal property will do. 在后一种情况下,正常的财产会做。

You can't do this I'm afraid. 你不能这样做我害怕。 That's one of the reasons I started writing MoXAML Power Toys , to provide the ability to convert automatic properties into Notify properties. 这是我开始编写MoXAML Power Toys的原因之一,它提供了将自动属性转换为Notify属性的能力。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM