4

As I understand it, properties can not return references, and since structs are value types, there's no way to return a reference to a struct via properties, which would enable:

public struct SomeStruct
{
   public int SomeMember { get; set; }
}
class foo
{
   private SomeStruct bar; 
   public SomeStruct Bar{ get { return bar; } set { bar = value; } }
}

//Somewhere else
foo f = new foo();
f.Bar.SomeMember = 42; //Error, this doesn't work

Will I have to resort to setMemberOfSomeStruct() or is there another way?

edit: Specifically, I want to avoid having to call new for structs like these all the time. I know that with an constructor SomeStruct(int), this would work:

f.Bar = new SomeStruct(42); //ugh
TravisG
  • 2,373
  • 2
  • 30
  • 47
  • Don't use mutable structs since they are evil. Use immutable structs. – Servy Apr 13 '12 at 14:07
  • Weird. Is this bad design in XNA? It has a struct Rectangle with 4 ints. I need to update just two of the 4 ints very often. Do I really need to create a new rectangle every time just to do this? – TravisG Apr 13 '12 at 14:08
  • Yes. Creating a new struct is not an expensive operation, it is very cheap. That's the whole reason for using structs in the first place. – Servy Apr 13 '12 at 14:09
  • So the operator new for structs allocates them on the stack? – TravisG Apr 13 '12 at 14:10
  • Not all of the time, but whenever it can, yes. This would be an example of a time that it could. – Servy Apr 13 '12 at 14:15
  • Your particular struct will be on the heap inside the memory of your class instance, no stack will be involved here - only for the class reference and when you get a copy of the struct from the class to a local variable. – Adam Houldsworth Apr 13 '12 at 14:16
  • @AdamHouldsworth The struct insode of foo is in the heap of another class, yes, but if he were to make it immutable and set it by creating a new one rather than with mutation the new struct would be crated on the **stack** of the method that's setting this property, not in the heap of some other object. It could of course be moved to the heap if it's in a closure or something like that, but that's another story. – Servy Apr 13 '12 at 14:19
  • @Servy The new copy would be created on the stack and then moved to the heap once it is set into the property of the class... not to mention, setting would set a copy ;-) – Adam Houldsworth Apr 13 '12 at 14:20
  • Yes, it would create a new struct on the heap, and then copy the memory to overwrite the memory of the old value of the struct in 'foo'. The only **allocation** of objects is a single struct on the stack. That struct is copied to a location on the heap. None of these operations are expensive as long as the struct is not overly large. – Servy Apr 13 '12 at 14:22
  • @Servy Indeed, I was just about to amend my comment to say that your point of allocation speed still stands. The cost of copying is entirely dependent on the size of the `struct`, but they also come with guidelines on size and content - so in short, using a `struct` comes with caveats and there tend to be only a handful of scenarios where structs are *more* relevant than classes. – Adam Houldsworth Apr 13 '12 at 14:24
  • 1
    Have you recently read Miguel de Icaza's [Modest Proposal](http://tirania.org/blog/archive/2012/Apr-11.html)? (A blog post a few days ago on this very concept) – Damien_The_Unbeliever Apr 13 '12 at 14:33
  • Me? No. But thanks for the link, I will read it now. – TravisG Apr 13 '12 at 14:37

2 Answers2

2

Make your struct implementations immutable and do this:

var newSomeStruct = new SomeStruct(42 /* Feeds SomeMember */);
var myFoo = new Foo();
myFoo.Bar = newSomeStruct;

public struct SomeStruct
{
    private int _someMember;

    public int SomeMember { get { return _someMember; } }

    public SomeStruct(int someMember)
    {
        _someMember = someMember;
    }
}

Immutable structs help preserve the value type semantics that are expected.

If you don't make it immutable, then the above code is still the only way to get this to work.

Alternatively, but not much nicer looking, expose a method on the class to set the class's copy of SomeStruct:

public void SetSomeMember(int val)
{
    _bar.SomeMember = val; // Note _bar in this example is a field, not a property.
}

I only offer this for completeness, I'd still go down the immutability route as there is consensus regarding "mutable structs are evil". Property getters is one gotcha, as is casting to interfaces - immutable structs solve these.

There is also another facetious point to make - don't assume that performance problems exist before performance problems actually exist. A class definition might be just as fast as a struct for the style of use you get from it. Profiling is king here.

Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
0

Looks like you have a mutable struct, which isn't recommended.

But to answer your question directly: create a copy, mutate that and then set the property with the mutated struct.

var barCopy = f.Bar;
barCopy.SomeMember = 42;
f.Bar = barCopy;

By the way:

As I understand it, properties can not return references.

Of course they can - properties of reference types return references from the getter.

Since structs are value types, there's no way to return a reference to a struct via properties.

Sure there is, you can return a reference to a boxed struct. Example:

 public IComparable Property { get { return 42; } }
Community
  • 1
  • 1
Ani
  • 111,048
  • 26
  • 262
  • 307
  • Isn't a boxed `struct` still a copy? http://blogs.msdn.com/b/abhinaba/archive/2005/10/05/477238.aspx – Adam Houldsworth Apr 13 '12 at 14:11
  • @Adam: A copy of what? In the example I provided, it will box every time (so in that sense, it is a copy), but you can of course box once and hold onto a stable reference to that box. – Ani Apr 13 '12 at 14:13
  • True, but that seems nonsensical to the OP's requirements. As for his comments about returning references, I assume you realise he was referring to returning references to value types. – Adam Houldsworth Apr 13 '12 at 14:14
  • @Adam: The section below isn't meant to help the OP with their immediate requirements but to clarify some misconceptions they have. The direct answer is right at the top. – Ani Apr 13 '12 at 14:15
  • When you have a property of a reference type you're still returning a **copy** of the reference. The fact that what you're copying is a pointer, rather than a value itself, doesn't change that properties never return references to variables. – Servy Apr 13 '12 at 14:17
  • @Servy Splitting hairs, yes true. Semantically speaking the OP is asking if there is anyway to return a reference to a struct such that the *same underlying instance* is changed, as per the semantics of reference types. – Adam Houldsworth Apr 13 '12 at 14:18