简体   繁体   English

正确编码直接访问Property C的支持字段#

[英]Proper Coding Direct Access to the backing field of a Property C#

I have seen some code and thought that something seems wrong with it, so I would like to know if it is acceptable for good coding or not, my first thought is no. 我已经看到了一些代码,并认为它看起来有些不对劲,所以我想知道它是否可以接受良好的编码,我的第一个想法是否定的。

Consider: 考虑:

class MyClass
{
    private string m_MySuperString;
    public string MySuperString
    {
        get { return m_MySuperString; }
        set { m_MySuperString = value; }
    }

    public void MyMethod()
    {
        if (blah != yada)
        {
             m_MySuperString = badabing;
        }
    }

    public void MyOtherMethod()
    {
        if (blah == yada)
        {
            m_MySuperString = badaboom;
        }
    }
}

Is this kind of direct access to the Backing Field an acceptable practice or is it bad coding - or should I ask what is the point of the Property Accessor, and if this is done internally in a class with public members , access is allowed by multiple components - is it possible to have a crash - I would venture in a multi threaded application a crash should be expected. 这种直接访问Backing Field是一种可接受的做法还是编码错误 - 或者我应该问一下Property Accessor的重点是什么,如果这是在公共成员的类内部完成的,那么多个访问权限是允许的组件 - 是否可能发生崩溃 - 我会冒险在多线程应用程序中发生崩溃。

Please any thoughts ? 请问有什么想法? I have looked at this Link on SO and others> Why use private members then use public properties to set them? 我在SO和其他人看过这个链接 > 为什么使用私有成员然后使用公共属性来设置它们?

EDIT 编辑

Let me be clear since there is good info being provided and rather respond to all answers and comments directly. 让我明确一下,因为提供了良好的信息,而是直接回复所有答案和评论。 I am not asking about what properties are for, not if I can do auto implemented properties, private setters, OnValueChange notifications, logic on the properties. 我不是在询问属性是什么,而不是我可以在属性上执行自动实现的属性,私有setter,OnValueChange通知,逻辑。 My question is in regards to accessing that backing field directly - for example if you have say a mutlithreaded scenario - isn't the whole point of the synclock on the getters/setters - to control access to the backingfield ? 我的问题是关于直接访问该支持字段 - 例如,如果你说一个多线程场景 - 不是getters / setter上synclock的全部 - 控制对支持域的访问? Will this kind of code be acceptable in that scenario - just adding a syncLock to the getter and setter ?? 在这种情况下,这种代码是否可以接受 - 只需将一个syncLock添加到getter和setter中? Keep in mind the code in the constructor of myClass is an example - the code can be in any additional method - such as the updated class - Method1 请记住,myClass构造函数中的代码是一个示例 - 代码可以是任何其他方法 - 例如更新的类 - Method1

END EDIT 结束编辑

Properties in Object Oriented Programming (OOP) help to enforce Encapsulation . 面向对象编程(OOP)中的属性有助于强制执行封装 The idea is that only the object itself is allowed to interact with its own data (ie fields). 这个想法是只允许对象本身与自己的数据(即字段)进行交互。 Access to the object's data from outside is only allowed through methods. 只允许通过方法从外部访问对象的数据。 In Java, for instance, you have to explicitly write get- and set-methods. 例如,在Java中,您必须显式编写get和set方法。 Properties in C# have a special syntax that combines both of these methods in one construct, but the getters and setters are in fact methods. C#中的属性有一个特殊的语法,它将这两种方法结合在一个构造中,但getter和setter实际上是方法。

This also means that an object is absolutely allowed to access its own fields directly. 这也意味着绝对允许对象直接访问自己的字段。

There are cases, however, where property getters and setters perform additional logic. 但是,有些情况下,属性getter和setter执行额外的逻辑。 A setter might raise the PropertyChanged event or do some validation. setter可能会引发PropertyChanged事件或进行一些验证。 A getter might combine several fields or yield a formatted or calculated value. getter可能会组合多个字段或生成格式化或计算值。 If you need this additional logic to be performed, then you must access the properties instead of the fields. 如果需要执行此附加逻辑,则必须访问属性而不是字段。 If a property is auto-implemented, then you have no choice (in C#), since the backing field is hidden and not accessible. 如果属性是自动实现的,那么您没有选择(在C#中),因为支持字段是隐藏的并且不可访问。 ( In VB it is hidden from IntelliSense but accessible from within the class .) 在VB中,它对IntelliSense是隐藏的,但可以从类中访问 。)

In the use case described , You can define this as follows using auto-implemented properties 在描述的用例中,您可以使用自动实现的属性将其定义如下

public string MySuperString{ get;  set ;}

you should use a backing filed if you need to do some input verification or the property is different than the internal fields for example 如果您需要进行输入验证,或者属性与内部字段不同,则应使用后备文件

public string FullName{ get { return firstName + LastName} } public string FullName {get {return firstName + LastName}}

another benefit of using properties is you can define them in an interface , which is better in the long run for future features to be added 使用属性的另一个好处是您可以在界面中定义它们,从长远来看,这将更好地添加未来的功能

I recommend checking out Chapter 8, Section 1 of @JonSkeet's C# In Depth (from which I've shamelessly taken the below snippets for the purpose of education) for more information on automatically implemented properties. 为了获得有关自动实现属性的更多信息,我建议查看@ JonSkeet的C#In Depth的第8章第8节(我已经无耻地将下面的片段用于教育目的)。 In short answer to your question, no, there's nothing wrong with this code. 简而言之,回答你的问题,不,这段代码没有错。

Consider that the following snippet: 考虑以下代码段:

public string Name { get; set; }

is compiled as 编译为

private string <Name>k__BackingField;
public string Name
{
     get { return <Name>k__BackingField; }
     set { <Name>k__BackingField = value; }
}

...so the compiler is already doing the work for you that you've done above. ...所以编译器已经为你完成了上面所做的工作。 There are ways to modify what it's doing, but those don't really answer the question. 有一些方法可以修改它正在做的事情,但那些并没有真正回答这个问题。 One example given in the book for thread safety is this: 书中给出的线程安全性的一个例子是:

//code above, plus
private static int InstanceCounter { get; set; }
private static readonly object counterLock = new object();

public InstanceCountingPerson(string name, int age) {
    Name = name;
    Age = age;
    lock (counterLock) // safe property access
    {
        InstanceCounter++;
        // and whatever else you have to do with the lock enabled
    }
}

--Which is a pattern also referenced in this SO question . - 这个SO问题中也提到一种模式。 However, as pointed out there, locks are (a) potentially slow, (b) might not actually ensure their job is done because they have to be released at some point, and (c) rely on the trust system, because they sort of naively assume that anything wanting to access that object will make proper use of the lock (not always true, at least not in some of the code I've seen :D ). 然而,正如那里所指出的,锁定(a)可能很慢,(b)实际上可能无法确保他们的工作完成,因为他们必须在某个时候被释放,并且(c)依赖于信任系统,因为他们有点天真地假设任何想要访问该对象的东西都会正确使用该锁(并非总是如此,至少在我看过的一些代码中没有这些:D)。 The advantage of the getter and setter methods is that you can enforce the pattern of using the lock (read: properly encapsulate the field, as others have suggested) for any instance of your class. getter和setter方法的优点是,您可以为类的任何实例强制使用锁的模式(读取:正确封装字段,正如其他人所建议的那样)。

Another pattern you might consider, however, is Inversion of Control. 但是,您可能会考虑的另一种模式是控制反转。 With a Dependency Injection container, you can specify the level of thread safety you are comfortable with. 使用Dependency Injection容器,您可以指定您熟悉的线程安全级别。 If you are comfortable with everyone waiting for a singleton instance of your object, you can declare that all references to the object's interface reference the same object (and must wait for the object to become available), or you can determine that a thread-safe instance of the object should be created each time it is requested. 如果您对等待对象的单例实例的所有人感到满意,则可以声明对对象接口的所有引用都引用相同的对象(并且必须等待对象变为可用),或者您可以确定线程安全每次请求时都应创建对象的实例。 See this SO answer for more details. 有关详细信息,请参阅此SO答案

Note: 注意:

Any peer-reviewed criticism of the above ideas will be graciously accepted and added to the answer, as I'm sort of a thread safety dilettante at this point. 任何经过同行评审的对上述想法的批评都将得到慷慨接受并加入到答案中,因为我现在处于一种线索安全的困境。

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

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