Setting property's property directly in C#

Lets consider that I have a public property called AvatarSize like the following,

public class Foo
{
  ...

  public Size AvatarSize
  {
    get { return myAvatarSize; }
    set { myAvatarSize = value; }
  }

  ...
}

Now if a target class wants to set this property, then they need to do it the following way,

myFoo.AvatarSize = new Size(20, 20);  //this is one possible way

But if I try to set it like this,

myFoo.AvatarSize.Height = 20;  //.NET style
myFoo.AvatarSize.Width = 20;  //error

the compiler get me an error stating that it cannot modify the return values. I know why it happens, but I would like it to support the second way also. Please help me with a solution.

P.S. Sorry if the title is absurd

Upvotes: 6

Views: 1046

Answers (7)

DreamSonic
DreamSonic

Reputation: 1472

Size is a structure. Being a ValueType it's immutable. If you change it's property like that, it will only modify an object instance in the stack, not the actual field. In your case AvatarSize property can only be set using a struct constructor: new Size(20, 20).

Upvotes: 10

Jon Skeet
Jon Skeet

Reputation: 1500495

This is really just an expansion of Petoj's answer. I wouldn't go for a mutable size - making things mutable leads to harder to understand code in my view.

Instead, introduce two new properties, AvatarHeight and AvatarWidth:

public class Foo
{
  ...

  public Size AvatarSize
  {
    get { return myAvatarSize; }
    set { myAvatarSize = value; }
  }

  public int AvatarHeight
  {
    get { return AvatarSize.Height; }
    set { AvatarSize = new Size(AvatarWidth, value); }
  }

  public int AvatarWidth
  {
    get { return AvatarSize.Width; }
    set { AvatarSize = new Size(value, AvatarHeight); }
  }

  ...
}

You still can't write myFoo.AvatarSize.Width = 20 but you can write myFoo.AvatarWidth = 20. Note that setting the width and height separately will be less efficient than setting them in one go.

This is the approach Windows Forms takes, by the way.

Upvotes: 4

Wayne Bloss
Wayne Bloss

Reputation: 5550

If you want to treat a struct like a class, you have to make a wrapper class that has an implicit conversion to the struct type. Below you can see the wrapper class (named Size, you can name it whatever you want, it doesn't matter), the Class1 class that has a Size property and then an example of how it's all used in the Form1 class:

EDIT: I updated the Size class with the inverse conversion (from System.Drawing.Size to this Size class) and some comments.

public class Size
{
    public Size(){}

    public Size(int width, int height)
    {
        this.Width = width;
        this.Height = height;
    }

    public int Width { get; set; }

    public int Height { get; set; }

    static public implicit operator System.Drawing.Size(Size convertMe)
    {
       return new System.Drawing.Size(convertMe.Width, convertMe.Height);
    }

    static public implicit operator Size(System.Drawing.Size convertMe)
    {
       return new Size(convertMe.Width, convertMe.Height);
    }
}

class Class1
{
    public Class1()
    {
        this.TheSize = new Size();
    }

    public Size TheSize { get; set; }
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        /// Style 1.
        Class1 a = new Class1();

        a.TheSize = new Size(5, 10);

        /// Style 2.
        Class1 c = new Class1();

        c.TheSize.Width = 400;
        c.TheSize.Height = 800;

        /// The conversion from our Size to System.Drawing.Size
        this.Size = c.TheSize;

        Class1 b = new Class1();

        /// The opposite conversion
        b.TheSize = this.Size;

        Debug.Print("b Size: {0} x {1}", b.TheSize.Width, b.TheSize.Height);


    }
}

Upvotes: 1

bang
bang

Reputation: 5221

The only way is to make your own Size type as a class (reference) instead of struct (value).

  public class Size
  {
    public Int32 Width;
    public Int32 Height;
  }

But this will of course make the Size loose some of the advantages of being a value type...

Upvotes: 2

Rasmus Faber
Rasmus Faber

Reputation: 49629

The only way you can do what you want is by defining

public class MutableSize{
  public int Height{get;set;}
  public int Width{get;set;}
}

and then having AvatarSize return one of those instead of Size.

Upvotes: 4

Fortyrunner
Fortyrunner

Reputation: 12782

Does these Size object have write properties for Height and Width? Or are they readonly?

Upvotes: 1

Peter
Peter

Reputation: 38465

You could create 2 new properties myFoo.AvatarSizeWidth and make this property change the Width same goes for Height..

Upvotes: 2

Related Questions