Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blindly converting structs to classes to hide the default constructor?

I read all the questions related to this topic, and they all give reasons why a default constructor on a struct is not available in C#, but I have not yet found anyone who suggests a general course of action when confronted with this situation.

The obvious solution is to simply convert the struct to a class and deal with the consequences.

Are there other options to keep it as a struct?

I ran into this situation with one of our internal commerce API objects. The designer converted it from a class to a struct, and now the default constructor (which was private before) leaves the object in an invalid state.

I thought that if we're going to keep the object as a struct, a mechanism for checking the validity of the state should be introduced (something like an IsValid property). I was met with much resistance, and an explanation of "whoever uses the API should not use the default constructor," a comment which certainly raised my eyebrows. (Note: the object in question is constructed "properly" through static factory methods, and all other constructors are internal.)

Is everyone simply converting their structs to classes in this situation without a second thought?

Edit: I would like to see some suggestions about how to keep this type of object as a struct -- the object in question above is much better suited as a struct than as a class.

like image 892
Jon Seigel Avatar asked Sep 15 '09 20:09

Jon Seigel


2 Answers

For a struct, you design the type so the default constructed instance (fields all zero) is a valid state. You don't [shall not] arbitrarily use struct instead of class without a good reason - there's nothing wrong with using an immutable reference type.

My suggestions:

  • Make sure the reason for using a struct is valid (a [real] profiler revealed significant performance problems resulting from heavy allocation of a very lightweight object).
  • Design the type so the default constructed instance is valid.
  • If the type's design is dictated by native/COM interop constraints, wrap the functionality and don't expose the struct outside the wrapper (private nested type). That way you can easily document and verify proper use of the constrained type requirements.
like image 104
Sam Harwell Avatar answered Sep 29 '22 08:09

Sam Harwell


The reason for this is that a struct (an instance of System.ValueType) is treated specially by the CLR: it is initialized with all the fields being 0 (or default). You don't really even need to create one - just declare it. This is why default constructors are required.

You can get around this in two ways:

  1. Create a property like IsValid to indicate if it is a valid struct, like you indicate and
  2. in .Net 2.0 consider using Nullable<T> to allow an uninitialized (null) struct.

Changing the struct to a class can have some very subtle consequences (in terms of memory usage and object identity which come up more in a multithreaded environment), and non-so-subtle but hard to debug NullReferenceExceptions for uninitialized objects.

like image 25
codekaizen Avatar answered Sep 29 '22 08:09

codekaizen