I understand why you would want to use a read-only property using the following syntax:
private int _MyInt;
public int MyInt
{
get { return _MyInt; }
}
This example probably isn't the best one because I think that read-only properties really shine in conjunction with a readonly
variable, but that's beside the point. What I don't understand is why use a write-only property using the following syntax:
private int _MyInt;
public int MyInt
{
set { _MyInt = value; }
}
This is how read-only properties are described in various books and tutorials. If you set the variable, you would conceptually read it at some point, at least internally to the class, but to read it even internally within the class you would do so by accesssing _MyInt
which I feel violates the spirit of encapsulation which properties try to enforce. Instead, why wouldn't you just use the full power of the property with different access modifies for accessing it as such:
private int _MyInt;
public int MyInt
{
set { _MyInt = value; }
private get { return _MyInt; }
}
Which of course can just be written
public int MyInt { set; private get; }
You still get the encapsulation, but restrict other classes from access, so its still write-only to outside classes.
Unless there is a case where you honestly would want to assign to a variable but never actually access it, in which case I would definite开发者_高级运维ly be curious about when this need would arise.
I have never come across a valid use-case for a write-only property. Honestly, if there is a valid use-case for a write-only property I think it is safe to say that the solution is poorly designed.
If you need "write-only" semantics you should use a method. For instance, another user has found an example of a user object that uses a 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, a read/write property is a set of methods that are designed to masquerade as a field. They look and feel like a field. It is for this reason that a read-only property makes sense because we are used to having fields and variables that we can read but cannot change. However there isn't a corresponding field or variable construct that is writable but not readable.
This is why I believe that creating an API that employs write-only properties is bad practice. It runs counter-intuitive to what I believe is the main goal of the property syntax in C#.
Edit: More philosophy... I believe that classes serve a functional purpose: they provide a container for related data to be held and manipulated. Take our User
class for example - this class will hold all pieces of information that pertain to a user in the system. We collect all these pieces of data and give them a single name: user. In this way we use classes to create abstractions. User
is an abstraction that allows us to reason about all the individual pieces of data that comprise a 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 are allowing someone to input data and not read it. Why would you disallow this? Most likely because the information that has been passed in has been transformed in some way that makes it unreadable to the passer.
So this means that a write-only property by definition must create side-effects that the caller cannot see (because if they could see them then there would be no reason to make the property write-only). The best construct in the C# language for setting a value with side-effects is the method.
I would highly recommend not using write-only properties because consumers of your API will find them confusing and frustrating. Even if you find a valid use-case for this syntax it doesn't justify its use.
Edit: Here is official recommendation from .Net Framework Design Guidelines for Developing Class Libraries -> Member Design Guidelines -> Property Design
Do not provide set-only properties.
If the property getter cannot be provided, use a method to implement the functionality instead. The method name should begin with Set followed by what would have been the property name...
Interesting question.
After some Googling, this is all I could find: a write-only property could be used to set a password on a User
object. Since passwords are usually stored in hashed form, there is (and should be) no way to retrieve a password after it has been set.
One use for a write-only property is to support setter dependency injection.
Let's say I had a class:
public class WhizbangService {
public WhizbangProvider Provider { set; private get; }
}
The WhizbangProvider is not intended to be accessed by the outside world. I'd never want to interact with service.Provider
, it's too complex. I need a class like WhizbangService to act as a facade. Yet with the setter, I can do something like this:
service.Provider = new FireworksShow();
service.Start();
And the service starts a fireworks display. Or maybe you'd rather see a water and light show:
service.Stop();
service.Provider = new FountainDisplay(new StringOfLights(), 20, UnitOfTime.Seconds);
service.Start();
And so on....
A common case I can see is if you only wanted a caller to be able to obtain a transformed version of your property. For example:
public int MyInt { set; }
public string MyIntAsString
{
get { return this.MyInt.ToString(); }
}
Obviously, this isn't a real example, but you get the picture.
EDIT:
After reading Thomas' example use case, then a real "transformation" type scenario could be to retrieve an encrypted version of the write-only property:
private string password;
public string ClearPassword { set { this.password = value; }
public string EncryptedPassword
{
get { return Encrypt(password); }
}
Sources I've read have suggested that if you honestly have a situation where you just created a write-only property, you should probably consider turning it into a method. And I typically agree.
Any information that must flow one way is useful through a write-only property. Generally we write classes for information to flow out of or in and out. In the case of write-only you have to think of situations where information should only flow in and not out. Usually this involves security type of information because we don't want a consumer to have any access in retrieving a secure piece of information. Passwords, CC numbers, etc...
When the information is not secure, e.g., when we don't mind anyone accessing it then we get the common get/set pattern. 99.9% of the time this is how properties are used. Since there are other ways, just as easy that can be more robust to achieve this, this is more of a semantic construct that was left in for symmetry than anything. One of the rare cases where something wasn't taken out and your left with "Why the heck did they remove that!".
The reason I can think of off the top of my head is because _myInt shows up at the top of the intellisense context menu.
I don't think accessing _myInt violates the spirit of encapsulation at all; it's a private member field of a class. Any code within the class SHOULD use the _myInt. It's private, after all.
The only thing that matters to the outside world is the public contract of the class. _myInt is a concern of the class itself, not part of the public facing contract.
And like I said - it's easier to grab _myInt with intellisense when you're coding.
I'm sure the feature is there simply for symetry with a get-only variable. As Aphex sort of vaguely implies, some things have no point and are only there because it's easier to leave it in than to remove it.
I have had cause for a write-only property.
In a .NET web-service, I have had to create a legacy ASMX web-service, as the URI is hard coded in hardware.
I'm a big fan of using Ninject for dependency injection, using constructor injection to satisfy all dependencies a class may have. For the most part, these dependencies would be declared private readonly fieldName
and assigned to in the constructor. The reason for this is that the dependencies of the class are not part of the class' responsibilities; they are dependencies.
However, the problem is whatever factory mechanism ASP.NET uses to create the class instance for a web-service relies on there being a constructor with no arguments, that scuppered my constructor injection.
I could have used a call from the default constructor to re-direct to an overloaded constructor making use of a ServiceLocator (anti)pattern, but I didn't fancy that.
Using the Ninject web extension, I inherited my service class from Ninject.Web.WebServiceBase
and employed property injection, marking the properties that Ninject would satisfy with an [Inject]
attribute.
Getting back to the point about injected services being dependencies for the class, rather than responsibilities that the type has, I don't want these dependencies properties accessed by other classes, so I mark the get property as private.
精彩评论