Freigeben über


Virtual properties anyone?

As part of the WinFX review team, I regularly review APIs for usability issues. One thing that we as a team have been highlighting as a potential issue is the use of virtual properties. Consider the following code snippet:

public class Class1
{
private string theString;

    public virtual string MyString
{
get{return theString;}
set{theString = value;}
}
}

public class Class2 : Class1
{
    public override string MyString
    {
        get{return "Ha ha!";}
        set{base.MyString = value;}
    }
}

Code that accesses the MyString property of an instance of Class1 might either return the actual string or “Ha ha!” depending on the actual runtime type.

The design guidelines suggest that properties should not be used if they perform some expensive operation (see Brad's post on a similar issue). Calling a virtual property or method is more expensive than calling non-virtual methods or properties so that is one reason for not creating virtual properties. Another reason is that we believe the code to access a property doesn't really suggest that the value of MyString depends on the runtime type of the object. Consider the following:

public

void DoSomething(Class1 c1){Console.WriteLine(c1.MyString);}

In this case, a developer might be surprised if calling DoSomething resulted in “Ha ha!“ being output to the console. We believe that to provide a consistent user experience, properties should mimic simple field access as much as possible. Thus virtual properties run the risk of breaking this consistency since in some cases, some properties work just like accessing a field while in other cases they work more like a virtual method call.

We're not suggesting that there is never a good reason for declaring virtual properties. We're just discouraging the use of virtual properties and encouraging the use of virtual methods instead.

However, I'd be interested in your feedback on this issue. Are we being too cautious?

Comments

  • Anonymous
    July 30, 2004
    The comment has been removed
  • Anonymous
    July 30, 2004
    There is a place for virtual properties in API design, but in majority of cases that we ran into during WinFx reviews, it was actually a design mistake. For example, we have seen lots of APIs where a property was virtual but it sill was just accessing the filed and there was no concrete scenarios for this property to do anything else. Sure, you can always come up with a corner case scenario, but at what cost:
    1. Virtual members are not being inlined. That means virtual property access is way more expensive than a filed access. This is not really acceptable for many system APIs.
    2. Virtual property (like any other virtual member) has a higher cost of design, has a negative impact on ability to version the API, and finally there are potential security implications.
  • Anonymous
    July 30, 2004
    The comment has been removed
  • Anonymous
    July 30, 2004
    I also have to vote in favor of Cyrus's argument. A property is syntatic sugar around a method pair (possibly a single method), and the intent is to shield the details of providing a value from all callers - the implementor is free to change the logic behind it whenever it is necessary.

    Well, why wouldn't a derived class find it necessary to change the behavior? Perhaps it wants to add a smart caching scheme on top of the base class. Perhaps it wants to do a remote lookup on top of a static local loopup.

    I also find the performance argument non-persuasive. Sure, if you sit there in a tight loop calling it 10000/second it begins to add up, but I think code that does that is more of a corner case then your example. Most code will call it once in a while where the extra performance hit of making a virtual method call is unnoticable. Optimization is good, but it should not get in the way of functionality, especially since this is totally under the control of the base class designer, who can choose to make the property virtual or not.

  • Anonymous
    July 30, 2004
    These are great comments, thanks for sharing them. Clearly some of you feel pretty strongly about this :-)

    We'll absolutely take your feedback into consideration during our reviews. Just to be a little clearer than I was in my original post though, our intention is not to completely prevent API designers from using virtual properties. We just want to make sure that they have very good reasons for using them. As I said, and as you have all reiterated, there are some very good reasons for using virtual properties. We do not intend to stop API designers from using virtual properties in those cases.

    One follow up question I have is - "How do you determine whether or not to make a property virtual?"
  • Anonymous
    July 30, 2004
    Steven- Perhaps I'm misunderstanding the intent of your question, but why is determining whether a property should be extensible any different than for a method, class, or anything else?

    I'd guess that you'd want to have some meaningful extensibility scenario. There'd have to be no issues for correctness, compatibility, or security. You'd need some amount of resources for programming / test / documentation.

    But don't you have all of that anyways for virtual methods? I guess I don't see why properties are being treated differently than methods. If you have a situtation where get/set makes sense, use a property. Otherwise, use a method. Whether it should be virtual or not doesn't seem to depend on the particular syntax you use to express it.
  • Anonymous
    July 30, 2004
    The comment has been removed
  • Anonymous
    July 30, 2004
    Steven,

    Here's a good considiration:
    I am given a base class with a property. I can't trust that property to not raise any events, call any methods, etc. just after I set its value from my own class (how could I otherwise set the value?).
    This is why I would like to override it and do some of my own logic prior to the logic of the base class, or even alter the behaviour all together.
  • Anonymous
    August 02, 2004
    Thanks again everybody. It seems obvious now, but thanks for making it clear to me. There is no reason for treating virtual properties any different to virtual methods. If there is a good reason for defining a virtual method, define it. If there isn't, don't.