Write-Only properties, what's the point?

I understand why you want to use a read-only property using the following syntax:

private int _MyInt; public int MyInt { get { return _MyInt; } } 

This example is probably not the best, because I think the read-only properties really shine when combined with the readonly variable, but this is next to the dot. I do not understand why using the write-only property uses the following syntax:

 private int _MyInt; public int MyInt { set { _MyInt = value; } } 

Here's how read-only properties are described in various books and textbooks. If you set a variable, you would conceptually read it at some point, at least inside the class, but to read it even inside the class you would do it by referring to _MyInt , which I feel violates the spirit of encapsulation whose properties try to enforce. Instead, why don't you just use the full power of a property with different permissions to access it as such:

 private int _MyInt; public int MyInt { set { _MyInt = value; } private get { return _MyInt; } } 

Which, of course, you can simply write

 public int MyInt { set; private get; } 

You still get encapsulation, but restrict access to other classes, so only external classes still write it.

If there is no case when you, frankly, want to assign a variable, but never get it, then I will definitely be curious when such a need arises.

+53
c # properties
Jan 14 '11 at 20:23
source share
9 answers

I have never come across a valid use case for the write-only property. Honestly, if there is a valid use case for a write-only record property, I think it is safe to say that the solution is poorly designed.

If you need write-only semantics, you should use the method. For example, another user found an example of a user object that uses the write-only property to set a password. This is a bad design:

 class User { public string Password { set { /* password encryption here */ } } } 

Ugh. This is much better:

 class User { public void SetPassword(string password) { /* password encryption here */ } } 

See, the read / write property is a set of methods that are designed to mask as a field. They look and feel like field. For this reason, the read-only property makes sense because we are used to the fact that we can read fields and variables, but cannot change them. However, there is no corresponding field construct or variable that is writable but not readable.

That's why I think creating an API that uses write-only properties is bad practice. It contradicts intuition of what I consider to be the main goal of property syntax in C #.

Edit: More philosophy ... I believe that classes perform a functional task: they provide a container for related data that needs to be stored and processed. Take, for example, the User class - this class will contain all pieces of information that relate to the user in the system. We collect all this data and give them one name: user. This way we use classes to create abstractions. User is an abstraction that allows us to reason about all the separate pieces of data that make up the user (password, name, birthday, etc.).

Now there are good abstractions and there are bad abstractions. I believe that write-only properties are bad abstractions, because you allow someone to enter data and not read it. Why don't you allow it? Most likely because the information that was transmitted was somehow transformed, which makes it unreadable to passers-by.

Thus, this means that the write-only property should, by definition, create side effects that the caller cannot see (because if they could see them, then there would be no reason for the property to be write-only). The best C # construct for setting a value with side effects is a method.

I would highly recommend not using write-only properties, because users of your API will find them confusing and disappointing. Even if you find a valid use case for this syntax, it does not justify its use.




Edit: Here is the official .Net Framework recommendation Design Guide for creating class librariesElement Design GuideProperty Design

Do not provide installation-only properties.

If the getter property cannot be provided, use the method to implement instead. The method name should begin with Set followed by the name of the property ...

+70
Jan 14 '11 at 20:26
source share

One use for a record property is only to support setter dependency injection.

Let's say I had a class:

 public class WhizbangService { public WhizbangProvider Provider { set; private get; } } 

WhizbangProvider is not intended to access the outside world. I would never want to interact with service.Provider , this is too complicated. I need a class like WhizbangService to act as a facade. But with the installer, I can do something like this:

 service.Provider = new FireworksShow(); service.Start(); 

And the service starts the fireworks. Or maybe you would rather see a water and light show:

 service.Stop(); service.Provider = new FountainDisplay(new StringOfLights(), 20, UnitOfTime.Seconds); service.Start(); 

And so on....

+11
Mar 17 '11 at 20:30
source share

The general case that I see is that you want the caller to be able to get a converted version of your property. For example:

 public int MyInt { set; } public string MyIntAsString { get { return this.MyInt.ToString(); } } 

Obviously, this is not a real example, but you get an image.

EDIT :

After reading an example of using Thomas, a real “conversion” scenario could be to get an encrypted version of a write-only property:

 private string password; public string ClearPassword { set { this.password = value; } public string EncryptedPassword { get { return Encrypt(password); } } 
+6
Jan 14 '11 at 20:28
source share

The sources I read suggested that if you have a situation where you just created a write-only property, you probably should consider turning it into a method. And I usually agree.

+2
Jan 14 '11 at 20:29
source share

Any information that should flow in one direction is useful with the write-only property. Typically, we write classes for information to exit from or from it. In the case of only for recording, you should think about situations where information should only come and not come out. This usually refers to the type of security, because we do not want the consumer to have any access to the search for a protected piece of information. Passwords, CC numbers, etc.

When information is not protected, for example, when we are not opposed to anyone accessing it, we get a common get / set pattern. 99.9% of the time is how properties are used. Since there are other ways that are just as lightweight that can be more reliable to achieve this, it is more a semantic construct that remains for symmetry than anything. One of the rare cases when something has not been taken out, and your left: "Why the hell did they delete it!".

+1
Jan 14 2018-11-11T00:
source share

The reason I can think of my head is because _myInt is displayed at the top of the intellisense context menu.

I don’t think that accessing _myInt generally violates the spirit of encapsulation; This is the private field of the class member. Any code inside the class SHOULD use _myInt. In the end, it is personal.

The only thing that matters to the outside world is the public class contract. _myInt is a problem of the class itself, and not part of the public contract.

And, as I said, it is easier to capture _myInt with intellisense when you code.

0
Jan 14 '11 at 20:28
source share

I am sure that the function exists simply for symetry with the get-only variable. As Aphex to some extent implies, some things are meaningless and only there, because it is easier to leave it than to remove it.

0
Jan 14 2018-11-11T00:
source share

I had a reason for a write-only property.

In the .NET web service, I had to create an outdated ASMX web service because the URI is hard-coded in hardware.

I'm a big fan of using Ninject to inject dependencies, using a constructor to satisfy all the dependencies a class can have. For the most part, these dependencies will be declared private readonly fieldName and assigned in the constructor. The reason for this is that class dependencies are not part of class responsibilities; they are dependencies.

However, the problem is what ASP.NET factory mechanism uses to instantiate the class for the web service, since it has a constructor with no arguments, which prevented the implementation of my constructor.

I could use the call from the default constructor to redirect to an overloaded constructor using the ServiceLocator (anti) pattern, but I did not like it.

Using the Ninject web extension, I inherited my class of service from Ninject.Web.WebServiceBase and used property embedding, marking the properties that Ninject would satisfy with the [Inject] attribute.

Returning to the question that embedded services are dependencies for a class, not responsibilities that a type bears, I do not want these dependency properties to be available to other classes, so I mark the get property as private.

0
Oct 02
source share



All Articles