Can structures contain fields of reference types

Can structures contain fields of reference types? And if they can this is bad practice?

+41
c # struct reference-type
Jun 03 '09 at 16:19
source share
6 answers

Yes, they can. Is that a good idea? Well, it depends on the situation. Personally, I rarely create my own structures in the first place ... I would consider any new user-defined structure with a certain degree of skepticism. I do not suggest that this is always the wrong option, it just needs a clearer argument than a class.

It would be a bad idea for a structure to have a reference to a mutable object, though ... otherwise you can have two values โ€‹โ€‹that look independent, but not like this:

MyValueType foo = ...; MyValueType bar = foo; // Value type, hence copy... foo.List.Add("x"); // Eek, bar list has now changed too! 

Variable structures are evil. Immutable structures with references to mutable types are covertly evil in different ways.

+66
Jun 03 '09 at 16:26
source share

Of course, and this is not a bad practice.

 struct Example { public readonly string Field1; } 

Reading is not necessary, but it is good practice to make the structure unchanged.

+14
Jun 03 '09 at 16:22
source share

Yes, it is possible, and yes, it is usually bad practice.

If you look at the .NET platform, you will see that almost all structures contain only primitive value types.

+3
Jun 03 '09 at 16:25
source share

Yes, they can.

It depends.

Many believe that the structure should be immutable, and in this case, a reference to an object may mean that it is not.

But it depends on the situation.

+2
Jun 03 '09 at 16:21
source share

The reason you cannot have mutable structures is due to the behavior of reference types. Read this article: http://www.yoda.arachsys.com/csharp/parameters.html

When you have a structure containing an object (everything that is not primitive, for example, int or double), and you copy an instance of the structure, the object inside is not copied "deep" because it is just a reference (pointer) to a memory cell containing actual class. Therefore, if you copy a modified structure containing instances of the class, the copy will refer to the same instances as the original one (therefore, the list of bars that was changed above).

If you absolutely need the structure to be mutable, make all instances of the class inside readonly or - this is bad practice - try to make sure that you never create a copy of the structure.

+2
Feb 11 2018-11-11T00:
source share

Since it got downvote, I'm trying to rewrite a bit to see if it can become clearer. This question is old; but good! Recently, I also came across several links that describe this in detail.

What I'm trying to add is that if you declare reference fields, you should be able to reason outside your own block: when someone uses your structure. The specific point I added was really only about declaring a readonly field in a structure; but in this case, the fields that you have in your structure can change their results; and it's hard to reason.

I stumbled upon this link where the programmer declared a class containing the readonly struct field. The field in his class is struct --- it a LinkedList<T>.Enumerator - and it broke because the readonly field --- its own class methods get a copy of the enumeration structure, and the state is copied and not dynamic.

But , if you fix its code by simply removing readonly from the struct field (which works); and then, however, if you then decide to make your own class a struct , now again, the consumer of your structure will not be able to use it as a reading field, otherwise they, in turn, will be bitten by the same problem. (And if that seems tricky because you don't have an enumerator, only really if it supports Reset!)

So, if this is not the clearest example, what I am doing is that you can talk about your own implementation, but if you are a structure, you also need to know about the consumers who copy your value and what they will get.

Below is an example that I found.

Its class is not a struct , but contains the m_Enumerator field (and the programmer presumably knows that it is a struct ).

It turns out that the methods of this class receive a copy of this value and do not work. --- You can really study this unit very carefully to understand this.

You can fix this by not making the field readonly ---, which already indicates confusion. But you can also fix this by declaring the field as an interface --- IEnumerator<int> .

But if you fix this by leaving the field declared as struct and declaring it not readonly , and then select your class definition as struct , then now, if someone declares an instance of your struct as readonly field in some class, they are lost again !

eg:.

 public class Program { private struct EnumeratorWrapper : IEnumerator<int> { // Fails always --- the local methods read the readonly struct and get a copy //private readonly LinkedList<int>.Enumerator m_Enumerator; // Fixes one: --- locally, methods no longer get a copy; // BUT if a consumer of THIS struct makes a readonly field, then again they will // always get a copy of THIS, AND this contains a copy of this struct field! private LinkedList<int>.Enumerator m_Enumerator; // Fixes both!! // Because this is not a value type, even a consumer of THIS struct making a // readonly copy, always reads the memory pointer and not a value //private IEnumerator<int> m_Enumerator; public EnumeratorWrapper(LinkedList<int> linkedList) => m_Enumerator = linkedList.GetEnumerator(); public int Current => m_Enumerator.Current; object System.Collections.IEnumerator.Current => Current; public bool MoveNext() => m_Enumerator.MoveNext(); public void Reset() => ((System.Collections.IEnumerator) m_Enumerator).Reset(); public void Dispose() => m_Enumerator.Dispose(); } private readonly LinkedList<int> l = new LinkedList<int>(); private readonly EnumeratorWrapper e; public Program() { for (int i = 0; i < 10; ++i) { l.AddLast(i); } e = new EnumeratorWrapper(l); } public static void Main() { Program p = new Program(); // This works --- a local copy every time EnumeratorWrapper e = new EnumeratorWrapper(pl); while (e.MoveNext()) { Console.WriteLine(e.Current); } // This fails if the struct cannot support living in a readonly field while (peMoveNext()) { Console.WriteLine(peCurrent); } Console.ReadKey(); } } 

If you declare a struct with an interface field, you wonโ€™t know what you have there, but still you can really learn more about what you get when you simply reference it! It is very interesting; but only because the language allows so many freedoms with struct : you need to start with something very simple; and add only what you can specifically substantiate!

Another point is that the link also states that you should define the default values โ€‹โ€‹as reasonable; what is impossible in the control field! If you inadvertently call the default constructor --- always possible with struct --- then you will get a null reference.

Also a final note. Many people advocate volatile structures and large volatile structures. But if you look inside, you usually find that they simply look at these objects in such a way that they can finally talk about behavior, and the structures do not leak in the area where these invariants could change.

... Too many people begin to explain structures as "Like a class, but ... x, y, z, 1, 2, alpha, beta disco." It needs to be explained as a pair of readonly values; period; besides the fact that you know something, you can start to talk about adding something!

The example I got accros is here:

https://www.red-gate.com/simple-talk/blogs/why-enumerator-structs-are-a-really-bad-idea/

-one
Nov 27 '17 at 14:21
source share



All Articles