开发者

How does SET works with property in C#?

开发者 https://www.devze.com 2022-12-29 18:31 出处:网络
I\'d like to know how set works in a property when it does more than just setting the value of a private member variable. Let\'s say I\'ve a private member in my class (private int myInt).

I'd like to know how set works in a property when it does more than just setting the value of a private member variable. Let's say I've a private member in my class (private int myInt).

For instance, I can make sure that the the value returned is not negative

get
{
  if(myInt < 0)
    myInt = 0;
  return myInt;
}

With SET, all I can do is affecting the private variable like so

set { myInt = value; }

I didn't see in any book how I can do more than that. How about if I wan't to do some operation before affecting the value to myInt? Let's say: If the value is negative, affect 0 to myInt.

set
{
  //Check if the value is non-negative, otherwise affect the开发者_如何学运维 0 to myInt
}

Thanks for helping


You can do what you want.

There's nothing to stop you having:

set
{
    if (value < 0)
        myInt = 0;
    else
        myInt = value;
}

(or some more compact version of this)

It's what the setters and getters were designed for.

You can add logging, debug asserts or even raise an exception if the value is out of bounds.

BUT

Users of your Setters and Getters will not expect them to do "lots" of processing or have any side effects. So they should only affect their backing variable and not go off and process 1000 text files (as an example). A connection to a database is fine, but if you're getting a lot of data back you should replace the Get with an explicit function.

Also, take note of what @StingyJack said in his answer though.


You can do anything in a "set". The specific example you asked:

set { 
  // Silently set to a more correct value
  myInt = value < 0 ? 0 : value; 
}

or

set { 
  // Always return error to caller
  if (value < 0) {
     throw new ArgumentException("value", "value cannot be negative.")
  }
  myInt = value; 
}

or

set { 
  // When debugging, warn the developer, in release adjust value silently
  Debug.Assert(value >= 0, "Value should 0 or larger");
  myInt = value < 0 ? 0 : value; 
}


Properties compile down to regular methods so you can execute anything inside a set statement. You theoretically don't even need to access a single member variable or use the value keyword. Albeit, it's generally accepted as bad practice to use a setter for more than setting a member variable.


You can do it like this:

set { myInt = value < 0 ? 0 : value; }

Whatever logic you want in there you can have, you can use value like any other Int...or whatever type your property is, value will be that type, do what you will with it :)


I can think of a few reasons - its far more common for the setter to be simple, but setters can be very useful in more complex situations:

The underlying storage type is different from the exposed type

This might be the case when you are creating a wrapper around some other object and want to hide the complexity

Sometimes the conversion might be simple (double to int etc...) and sometimes it might be more complex (Xml to some strongly typed object).

class ThingWrapper
{
    public Thing Thing {get; set;}

    public int SomeProperty
    {
        get
        {
            return int.Parse(this.Thing.SomeProperty);
        }
        set
        {
            Thing.SomeProperty = value.ToString();
        }
    }
}

You want to prevent a property from changing

Perhaps you have some sort of object exposing a long-running background task which is run in another thread, and you wish to prevent the user from changing properties while that task is running.

You need to detach from events

You might have some object which exposes events that you subscribe to, and you also want to be able to set that object (for some reason). In this case you need to make sure that you detach your event handlers from the old object and reattach to the new object.


A property like this:

public int SomeValue
{
    get { return _SomeValue; }
    set { _SomeValue = this; }
}

is basically this:

public int SomeValue { get; set; }

public int get_SomeValue()
{
    return _SomeValue;
}

public void set_SomeValue(int value)
{
    _SomeValue = value;
}

so anything you could put into two methods like that is valid for the two property accessor methods.


Like all of these answers have said, you can do whatever you want in a set. That doesn't mean that you should...

Take the following somewhat contrived example

Public Class MyClass

 Private m_myValue as String

 Public Property MyValue as String
  Get
   If String.IsNullOrEmpty(m_myValue) Then
    Return String.Empty
   Else
    Return m_myValue
   End If
  End Get
  Set (Value as String)
   If String.IsNull(m_myValue) = False Then
    m_myValue = Value
   End If
  End Set
 End Property

 Public Function GetLengthOfMyValue() as Integer
  Return m_myValue.Length
 End Function

End Class

If you were to run the following snippet, the _len2 call would give you an exception because its not extended the same null value protections that the property is offering.

Dim _mc as New MyClass()
Dim _len1 as Integer = _mc.MyValue.Length
Dim _len2 as Integer = _mc.GetLengthOfMyValue()

Now, like I said this is a contrived example, but I do see it happen often enough in practice, and in many cases it adds subtle variances in behavior that can lead to bugs or other unintended consequences.

  • Should the function be using the property? Whats your preference (has your org's coding standards already decided that for you)?
  • Is there a better way to accomplish what you want without code duplication?

You may want to think about it a bit before using this pattern.

0

精彩评论

暂无评论...
验证码 换一张
取 消