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.
-
Put it in its own assembly and have the MyStruct() without the args as a Internal (Friend in VB). Have the Factory in the same assembly as MyStruct() but with a Public accessor.
Now the factory can access the no args MyStruct, but anything calling from outside the assembly must use the Factory.
Edit: My bad, I failed to take into account that this is a struct. You can't do this with a struct, only with a class - in which case, my previous statement stands.
Jon Skeet : You can't write your own paramaterless constructors for value types, so you can't define one to be internal.Matt Cruikshank : ...or Reflection, but yeah, you've got the best answer I can think of.BenAlabaster : Jon: Yeah, you're right - I instantly read this as Class - my mistake. You would have to make the struct a class. -
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.
BCS : Crud.... & Yes, I need value semantics and the fact I'm throwing these things around like popcorn plus some "extra" constraints result in a major perf hit if I switch to classesJon Skeet : Have you *measured* the performance to know for sure that it would actually be a perf hit? Try it with a class, making it immutable to keep the value type semantics.plinth : Hee - messing around in il is messy. You are my tautological hero, Jon.BCS : Re: perf the hit is in the constructors (See the new disclosure) when memory is allocated.Jon Skeet : I would fix it to be less tautological, but then it would mess up your comment ;)Jon Skeet : @BCS: Is D really sluggish at memory allocation then? In .NET I'd have no worries about creating millions of objects if necessary. Of course, one of the nice things about using a class is that often you can get away *without* creating a new object - just keep the reference unless you need to mutate.BCS : I need to create 10Ks (1+ per token in kloc files) or so distinct objects per run and the difference between stack based struct and heap based objects is not trivial. Some of this is because D, with it's system level stuff, can't use some of the GC optimizations c# can.BCS : For context, I expect about a 25-50% of the data structures created to be of this type.Jon Skeet : Are you actually gaining much by doing code conversion here? I've never been much of a fan of writing in one language and then converting to another. I'd usually rather just write in the target language to start with. It may be a bit more painful in general, but it avoids this sort of issue.BCS : The major down side of D is that the tools suck, IMHO the only up side to C# it that the tools are world class. -
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.
BCS : you can in a static method in the struct, as my factory method does.BCS : The primary constraint is to disallow default initializations. I want to force the code to explicitly provide all the values. -
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.
0 comments:
Post a Comment