Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I enforce using a factory on a struct in C#

Tags:

c#

struct

factory

I have a c# struct where I need to forbid calling the no args constructor on it.

MyStruct a;
/// init a by members   // OK
MyStruct b = MyStruct.Fact(args); // OK, inits by memebers

MyStruct s = new MyStruct(); // can't have that

I'm doing this mostly to force explicet values for all members as there are no valid default values and all members must have valid values.

In C++ this would be easy, add a private constructor but c# doesn't allow that.

Is there a way to prevent the above?

I really need to enforce using a factory so preventing all public constructor calls would work just as well.


Full discloser: to avoid a mono dependency, the c# app is being automatically translated to D where new Struct() results in a pointer and this is mucking things up for me. However this question is relevant despite that so just ignore it.

like image 645
BCS Avatar asked Dec 04 '08 20:12

BCS


People also ask

Can I write a default constructor in structure?

C# does not allow a struct to declare a default, no-parameters, constructor. The reason for this constraint is to do with the fact that, unlike in C++, a C# struct is associated with value-type semantic and a value-type is not required to have a constructor.

Can a struct have a constructor?

struct can include constructors, constants, fields, methods, properties, indexers, operators, events & nested types. struct cannot include a parameterless constructor or a destructor. struct can implement interfaces, same as class. struct cannot inherit another structure or class, and it cannot be the base of a class.

Does a struct need a constructor?

Technically, a struct is like a class , so technically a struct would naturally benefit from having constructors and methods, like a class does.

When use factory method?

The Factory Method pattern is generally used in the following situations: A class cannot anticipate the type of objects it needs to create beforehand. A class requires its subclasses to specify the objects it creates. You want to localize the logic to instantiate a complex object.


3 Answers

You can't. All structs have a public parameterless constructor by definition in C#. (In the CLR almost none of them do, but they can always act as if they have.) See this question for why you can't define your own parameterless constructors on structs (in C#, anyway).

In fact, you can prevent this statement if you're happy to write your value type in IL. I've just checked, and if you make sure that your value type only has a parameterless constructor, and make it internal, you won't be able to write MyStruct ms = new MyStruct(); But this doesn't prevent:

MyStruct[] array = new MyStruct[1];
MyStruct ms = array[0];

which works around the new restriction - so it doesn't really buy you anything. That's quite good really, as messing around in IL would be messy.

Are you sure you really want to be writing a struct in the first place? That's almost never a good idea.

like image 76
Jon Skeet Avatar answered Oct 04 '22 06:10

Jon Skeet


You can't.

All values in a struct must be initialized at construction time, and there's no way to do that outside the constructor.

What exactly are you trying to accomplish by doing that? Structs are value types, so you'll get a "new" struct for most operations. It will be very difficult to enforce the sorts of constraints you'd use a factory for on a struct.

like image 23
MrKurt Avatar answered Oct 04 '22 05:10

MrKurt


Anyone can create a struct at any time without calling a constructor, as long as they have access to the struct. Think about it this way:

If you create an array of objects with 1000 elements, they all get initialized to null, so no constructors are called.

With structs, there is no such thing as null. If you create an array with 1000 DateTime objects, they are all initialized to zero, which equals DateTime.Min. The designers of the runtime chose to make it so you could create an array of structs without calling the constructor N times--a performance hit many people wouldn't realize was there.

Your factory idea is a good one, though. Would it meet your needs to create an interface and expose that, but make the struct private or internal? That's about as close as you'll get.

like image 25
Neil Avatar answered Oct 04 '22 05:10

Neil