I am writing an application in C# which is going to do extensive calculations. Everything is going around basic struct - Value. It is basically double with some additional parameters (accuracy etc.) It has to be a struct, because there will be too many of them created to afford heap allocation. Now, I need to make sure they all are correctly initialized. I cannot declare default explicit constructor, though I am provided default constructor, which initializes everything with 0, which does not make sense in my domain.
And there is no way to deny creating an instance without calling my constructor with parameters either...?
Basically what I need is this test to pass:
[Test]
public void HowDoesThisStructureInitializeByDefault()
{
Value v = new Value(); - if this did not compile - it would have been ok!
Assert.AreEqual(0, v.Val); - passes
Assert.AreEqual(-1, v.Accuracy); - fails
}
It would be OK to throw an exception if no constructor has been explicitly called and structure is still accessed, but checking that all the time would take too much time.
I am almost losing hope now, please help!
Why can't you define an explicit constructor? This is what they're for. Moreover, why do you think you "can't afford heap allocation"? Heap allocation is very cheap in managed languages. How have you tested this assumption that you can't afford heap allocation, or indeed that heap allocation is more expensive in the first place?
(For a type consisting of "a double and several parameters", I suspect you're up in a size where heap allocation is actually cheaper and more efficient)
In any case, you can't prevent a user from calling the default constructor on a value type, if he so desires. All you can do is make sure that a better way to initialize the value exists, such as a non-default constructor, or if you can't create one for whatever reason, a function which creates and initializes your value type when called.
But of course, you have no guarantees that people actually call it.
Edit: Heap allocation in .NET basically consists of just a simple stack push operation. That's the nice thing about managed (and garbage-collected) languages. The runtime essentially uses a big stack as its heap, so each allocation just increments the stack pointer a bit (after checking that there's enough free memory, of course). The garbage collector then takes care of compacting the memory when necessary.
So the heap allocation itself is ridiculously cheap. Of course, the additional GC pressure might slow you down again (Although as far as I know, the time required for a GC pass depends only on the number of live object, not on the ones to be GC'ed, so having countless "dead" objects lying around may not be a big problem), but on the other hand, stack allocation isn't free either. Value types are passed by value, so every time you pass your type as a parameter to a function, or return it, a copy has to be made. I don't know how big your value is, but a double is 8 bytes, and given that you have a few extra parameters, I'll assume 32 bytes. That might be so big that the extra copying required for valuetypes makes it slower than if you'd used heap allocation. Perhaps.
As you can see, there are advantages to both value- and reference-types. I can't say which one is faster in your case, but if I were you, I'd be very careful making this kind of assumptions. If possible, structure your code so you can switch between a reference- and valuetype implementation, and see which works best. Alternatively, write smaller tests to try to predict how each would perform on a large scale.
You can't get rid of the default constructor (Jon Skeet, of course, answered why very well at Why can't I define a default constructor for a struct in .NET?), but you could create a factory class that allows you to define your structure values with properly initialized parameters. You could use unit tests with mock/verify to make sure that when new values are created by your code they use the factory. This would be a convention that you would need to enforce as the compiler will not enforce it for you.
public static class StructFactory
{
public static Value DefaultValue()
{
Value v = new Value();
v.Value = 0.0;
v.Accuracy = 15; /* digits */
return v;
}
}
...
Value v = StructFactory.DefaultValue();
Struct fields are initialized to zero (or null, or in general default(T)).
If you want the initial value of Accuracy to be -1, you could implement the Accuracy property such that when the underlying field == 0, the property returns -1.
One possibility:
struct Value
{
int _accuracyPlusOne;
public int Accuracy
{
get { return _accuracyPlusOne - 1; }
get { _accuracyPlusOne= value + 1; }
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With