C# - Calling a struct constructor that has all defaulted parameters - c#

I ran into this issue today when creating a struct to hold a bunch of data. Here is an example:
public struct ExampleStruct
{
public int Value { get; private set; }
public ExampleStruct(int value = 1)
: this()
{
Value = value;
}
}
Looks fine and dandy. The problem is when I try to use this constructor without specifying a value and desiring to use the defaulted value of 1 for the parameter:
private static void Main(string[] args)
{
ExampleStruct example1 = new ExampleStruct();
Console.WriteLine(example1.Value);
}
This code outputs 0 and does not output 1. The reason is that all structs have public parameter-less constructors. So, like how I'm calling this() my explicit constructor, in Main, that same thing occurs where new ExampleStruct() is actually calling ExampleStruct() but not calling ExampleStruct(int value = 1). Since it does that, it uses int's default value of 0 as Value.
To make matters worse, my actual code is checking to see that int value = 1 parameter is within a valid range within the constructor. Add this to the ExampleStruct(int value = 1) constructor above:
if(value < 1 || value > 3)
{
throw new ArgumentException("Value is out of range");
}
So, as it stands right now, the default constructor actually created an object that is invalid in the context I need it for. Anyone know how I can either:
A. Call the ExampleStruct(int value = 1) constructor.
B. Modify how the default values are populated for the ExampleStruct() constructor.
C. Some other suggestion/option.
Also, I am aware that I could use a field like this instead of my Value property:
public readonly int Value;
But my philosophy is to use fields privately unless they are const or static.
Lastly, the reason I'm using a struct instead of a class is because this is simply an object to hold non-mutable data, should be fully populated when it is constructed, and when passed as a parameter, should not be able to be null (since it is passed by value as a struct), which is what struct's are designed for.

Actually, MSDN has some good guidance on struct
Consider defining a structure instead of a class if instances of the
type are small and commonly short-lived or are commonly embedded in
other objects.
Do not define a structure unless the type has all of the following
characteristics:
It logically represents a single value, similar to primitive types
(integer, double, and so on).
It has an instance size smaller than 16 bytes.
It is immutable.
It will not have to be boxed frequently.
Notice that they are considerations for considering a struct, and its never a "this should always be a struct". That is because the choice to use a struct can have performance and usage implications (both positive and negative) and should be chosen carefully.
Notice in particular that they don't recommend struct for things > 16 bytes (then the cost of copying becomes more expensive than copying a reference).
Now, for your case, there is really no good way to do this other than to create a factory to generate a struct for you in a default state or to do some sort of trick in your property to fool it into initializing on first use.
Remember, a struct is supposed to work such that new X() == default(X), that is, a newly constructed struct will contain the default values for all fields of that struct. This is pretty evident, since C# will not let you define a parameterless constructor for a struct, though it is curious that they allow all arguments to be defaulted without a warning.
Thus, I'd actually suggest you stick with a class and make it immutable and just check for null on the methods that it gets passed to.
public class ExampleClass
{
// have property expose the "default" if not yet set
public int Value { get; private set; }
// remove default, doesn't work
public ExampleStruct(int value)
{
Value = value;
}
}
However, if you absolutely must have a struct for other reasons - but please consider the costs of struct such as copy-casts, etc - you could do this:
public struct ExampleStruct
{
private int? _value;
// have property expose the "default" if not yet set
public int Value
{
get { return _value ?? 1; }
}
// remove default, doesn't work
public ExampleStruct(int value)
: this()
{
_value = value;
}
}
Notice that by default, the Nullable<int> will be null (that is, HasValue == false), thus if this is true, we didn't set it yet, and can use the null-coalescing operator to return our default of 1 instead. If we did set it in the constructor, it will be non-null and take that value instead...

I don't think it's good design to have a struct ExampleStruct such that
default(ExampleStruct)
i.e. the value where all instance fields are zero/false/null, is not a valid value of the struct. And as you know, when you say
new ExampleStruct()
that's exactly the same as default(ExampleStruct) and gives you the value of your struct where all fields (including "generated" fields from auto-properties) are zero.
Maybe you could do this:
public struct ExampleStruct
{
readonly int valueMinusOne;
public int Value { get { return valueMinusOne + 1; } }
public ExampleStruct(int value)
{
valueMinusOne = value - 1;
}
}

I guess the compiler is actually picking the automatic default ctor for structs here http://msdn.microsoft.com/en-us/library/aa288208(v=vs.71).aspx, rather than using your ctor with the default values.
added references:
http://csharpindepth.com/Articles/General/Overloading.aspx (Optional parameters section)

Although some languages (CIL if nothing else) will allow one to define a struct constructor such that new T() has fields set to something other than their "all zeroes" defaults, C# and vb.net (and probably most other languages) take the view that since things like array elements and class fields must always be initialized to default(T), and since having them be initialized to something which didn't match new T() would be confusing, structures shouldn't define new T() to mean something other than default(T).
I would suggest that rather than trying to jinx a default parameter in a parameterized constructor, you simply define a static struct property which returns your desired default value, and replace every occurrence of new ExampleStruct() with ExampleStruct.NiceDefault;.
2015 Addendum
It appears that C# and VB.NET may ease the prohibition against defining parameterless struct constructors. This may cause a statement like Dim s = New StructType() to assign s a value which is different from the value given to new array items of type StructType. I'm not terribly keen on the change, given that new StructType is often used in places where something analogous to C#'s default(StructType) would be more appropriate if it existed. VB.NET would allow Dim s As StructType = Nothing, but that seems rather hokey.

why do you have public ExampleStruct(int value = 1) : this() ?
shouldn't it be public ExampleStruct(int value = 1)? I think the :this() is creating the no-parameter constructor.

Related

Why are we allowed to use const with reference types if we may only assign null to them?

The question is actually very straightforward. The following code throws the exception right below it:
class Foo
{
public const StringBuilder BarBuilder = new StringBuilder();
public Foo(){
}
}
Error:
Foo.BarBuilder' is of type 'System.Text.StringBuilder'. A const field
of a reference type other than string can only be initialized with
null.
MSDN says this, which I understand and it makes sense from const perspective:
A constant expression is an expression that can be fully evaluated at
compile time. Therefore, the only possible values for constants of
reference types are string and a null reference.
However, I don't see the reason why or where we would use null constant. So why in the first place that a reference type (other than string) can be defined with const if it can be only set to null and if it was a deliberate decision (which I believe it is) then where can we use constant with null values?
Update:
When we think of an answer, please let's think differently than "We have this so why not that..." context.
From MSDN
when the compiler encounters a constant identifier in C# source code (for example, months), it substitutes the literal value directly into the intermediate language (IL) code that it produces. Because there is no variable address associated with a constant at run time, const fields cannot be passed by reference and cannot appear as an l-value in an expression.
Because reference types (other than null, and strings which are special) need to be constructed at run time, the above would not be possible for reference types.
For reference types, the closest you can get is static readonly:
class Foo
{
// This is not a good idea to expose a public non-pure field
public static readonly StringBuilder BarBuilder = new StringBuilder();
public Foo(){
}
}
Unlike const substitution (in the calling code), static readonly creates a single shared instance of the reference type which has subtle differences if assembly versions are changed.
Although the reference cannot (normally) be reassigned, it doesn't preclude calling non-pure methods on the StringBuilder (like Append etc). This is unlike consts, where value types and strings are immutable (and arguably should be "eternal").
However, I don't see the reason why or where we would use null constant.
Null constants are useful as sentinel values.
For example, this:
public class MyClass
{
private const Action AlreadyInvoked = null;
private Action _action;
public MyClass(Action action) {
_action = action;
}
public void SomeMethod()
{
_action();
_action = AlreadyInvoked;
}
public void SomeOtherMethod()
{
if(action == AlreadyInvoked)
{
//...
}
}
}
Is much more expressive than this:
public class MyClass
{
//...
public void SomeMethod()
{
_action();
_action = null;
}
public void SomeOtherMethod()
{
if(action == null)
{
//...
}
}
}
The source code for the Lazy<T> class shows Microsoft used a similar strategy. Although they used a static readonly delegate that can never be invoked as a sentinel value, they could have just used a null constant instead:
static readonly Func<T> ALREADY_INVOKED_SENTINEL = delegate
{
Contract.Assert(false, "ALREADY_INVOKED_SENTINEL should never be invoked.");
return default(T);
};
As you state in the question, there is one reference type that can be put into a const reference - strings. The compiler special-cases this and puts the strings into the compiled output and allows them to be read into the reference type at runtime.
Of course this begs the question - why not have strings be the only reference types that can be const, as long as we're special-casing them anyway? To that, I can only speculate that adding a special case in the compiler is simpler and less problematic than adding a special case in the language. From a language perspective, a string is just a reference type, even if the compiler has special handling to create instances of it from string literals and compiled resources.
I think that you are asking that why reference type with null allow as a constant.
I think you are right that it does not make much sense but it is useful if you have designed your own library and if you want to compare with null but want to give special meaning ( like comparing with your library value only rather then directly null)
public class MyClass
{
public const MyClass MyClassNull = null;
public MyClass()
{
}
}
it usage like this.
object obj = GetMyClass();
if(obj == MyClass.MyClassNull) // This going to convert to actual null in MSIL.
{
}

How to declare an array of structs inside a struct?

Using Visual Studios 2010 C#
so i am making a struct of data for a c# project, that will among it's members include an array of type another struct. So for example here is a stripped down idea of my code:
private struct scores
{
public double finalScore;
};
private struct information
{
public string name;
public scores[] scoreList;
};
I am getting the following warning when I write this:
Error 1 'WindowsFormsApplication1.main.information.scoreList': cannot
have instance field initializers in structs
I am wondering what is the correct way to declare the scores[] scoreList aspect of the struct information, so I can have the array size set to 10?
Things I have tried:
If I try
public scores[] scoreList = new scores[10]
I get the following error
Error 1 'WindowsFormsApplication1.main.information.scoreList': cannot
have instance field initializers in structs
In structs you can do initialization within constructors only:
struct information {
public string name;
public scores[] scoreList;
// Constructor
public information(String nameValue) {
name = nameValue;
scoreList = new scores[10]; // <- It's possible here
}
};
The problem here is that you're making the structs private, which means you can't make instances of them. Make them public. And also get rid of the ; at the end
public struct scores
{
public double finalScore;
}
public struct information
{
public string name;
public scores[] scoreList;
}
I typically don't use structs because of their OO limitations and the fact that they're not nullable. There are however several structs in .Net : DateTime, int, float etc...
You can't do this. The reason is that structs are value types. The default constructor of a struct is a parameterless constructor that initializes all fields to their default value. You don't have control over this constructor because they are value types.
The best way to show this is e.g. through an array. Say you make an array of a a class type, e.g. new object[10]. The items of this array will be initialized to null. However, when you would make an array of structs, e.g. new information[10], the items of the array will be valid instances already. However, the constructor on these items won't have run and all fields will have been initialized to their empty values. In your case, this means that all fields will be null.
There are two solutions to this. The first solution is to create a factory method, e.g.:
public static information CreateNew()
{
var result = new information();
result.scoreList = new scores[10];
return result;
}
This will work. You just create an instance with information.CreateNew() instead of new information(), and you will have an initialized information. However, a far more easy solution will be to just use a class instead.
There are three ways to have a structure behave as a value-type array of structs:
Use unsafe code to include one or more fixed arrays of primitives within your structure; have your indexed get/put accessors assemble a structure out of information stored in those arrays. For example, if you wanted to behave like an array of Point, one could have a fixed array for all the X coordinates and a fixed array for all the Y coordinates, and then have the this[int] getter construct a Point by combining an X and Y value, and the this[int] setter store the X and Y values from the passed-in point.
Have multiple fields of your struct type, and have the this[int] getter read from one of them and have the this[int] setter write to one of them. There are ways by which this can be made not too horribly inefficient, but it's still rather icky.
Have the structure hold a private array of the appropriate structure type. The get and set accessors should look something like:
T[] _array;
T this[int index] {
get {
T[] temp_array = _array;
if (temp_array == null) return default(T);
return temp_array[index];
}
set {
do
{
T[] was_array[] = _array;
T[] new_array = (temp_array == null) ? new T[size] : (T[])(temp_array.Clone());
temp_array[index] = value;
} while (System.Threading.Interlocked.CompareExchange(ref _array, new_array, was_array) !=
was_array);
}};
This approach will allow the get indexer to run faster than would be possible with the second approach (and probably the first as well), and unlike the first approach it will work with generic types. The primary weakness with this approach is that every time its set accessor is run it must make a new copy of the array. If writes are much less frequent than reads, however, that might not be a problem. Incidentally, as written, the code should be fully thread-safe--something which is possible with mutable structures, but not possible with structures that pretend to be immutable.

Best way to use Value types as Reference types?

I've been using something similar to this whenever I needed to reference a Value type:
public class RefHost<T> {
public RefHost(T val)
{
Value = val;
}
private T _value;
public T Value {
get {
return _value;
}
set {
_value = value;
}
}
}
What I'm wondering is there a built in way or an easier way to use an existing Value type as a Reference type?
Example:
public class Editor {
public RefHost<int> Blah = new RefHost<int>(5);
// Some kind of timer to increase the value of Blah every few ticks
}
Kind of like that where the user of Editor specifies a value type that needs to be changed, and there can be multiple instances of Editor each with it's own value. I used the timer as an example but most of the time it's a user control like a slider.
I think you are looking for Tuple.
Sure there is. If you want to pass it as a reference type to a method just use the ref modifier:
public static void Main()
{
int n = 1;
Test(ref n);
Console.WriteLine(n); //will print out 2 and not 1.
Console.ReadKey(true);
}
public static void Test(ref int x)
{
x = 2;
}
What's wrong with this?
public class Editor {
public int Blah = 5;
// Some kind of timer, with a handler like:
void MyTimerTicker(object sender, EventArgs e)
{
this.Blah += 1;
}
}
Boxing and unboxing is what this is called. Your solution might be more type safe though.
See http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx
Replace the property and backing field with a public field. While it is generally good for classes to use properties rather than fields, the whole purpose of your type is to be a simple mutable container for a single value-type instance; the state encapsulated by any reference to an instance of the type should be precisely defined by two things:
The value of the `Value` member
The whereabouts of all other references to the instance that exist anywhere in the universe
If two instances have the same Value, and if within the entire universe only one reference exists to each one, the two references should be semantically indistinguishable [since in both cases the set of "other references" that exist to the instances would be empty]
While there are various helper methods that a type of that style might implement, it would be impossible for a future version of the type to add additional state without violating the expected semantics. Since the whole purpose of the type is to behave like a class object containing a single field of type T, code will be clearest if one writes the object to in fact be a class object containing a single field of type T.
BTW, if you don't want to define a custom type, another option is to use a single-element T[1]. That will use a little bit of extra storage to hold the dimension, and adding [0] to all references will be a little uglier than .Value, but such an approach will nonetheless work pretty simply.

Overwriting Default values in C# structs

For an assignment I have to write a Tribool class in C# using a struct. There are only three possible tribools, True, False, and Unknown, and I have these declared as static readonly. Like this:
public static readonly Tribool True, False, Unknown;
I need my default constructor to provide a False Tribool, but I'm not sure how to go about this. I've tried Tribool() { this = False; } and Tribool() { False; } but I keep getting a "Structs cannot contain explicit parameterless constructors" error.
The assignment specified that the default constructor for Tribool should provide a False Tribool. Otherwise, a user should not be able to create any other Tribools. I don't really know what to do at this point. Any advice would be greatly appreciated. Thanks.
Just to add a bit to Jason's answer: design your struct carefully so that the default value is meaningful. As an example, consider the Nullable<T> struct. The desired behaviour is that when you say
Nullable<int> x = new Nullable<int>(); // default constructor
that the resulting value is logically null. How do we do that? The struct is defined something like this:
struct Nullable<T>
{
private readonly T value;
private readonly bool hasValue;
public Nullable(T value)
{
this.value = value;
this.hasValue = true;
}
...
So when the default constructor runs, hasValue is automatically set to false and value is set to the default value of T. A nullable with hasValue set to false is treated as null, which is the desired behaviour. That's why the bool is hasValue and not isNull.
As the error is telling you, you absolutely can not have a parameterless instance constructor for a struct. See ยง11.3.8 of the C# 3.0 language specification:
Unlike a class, a struct is not permitted to declare a parameterless instance constructor.
The language provides one for you known as the default constructor. This constructor returns the value of the struct where are fields have been set to their default value.
Now, what you could do is have the default value of the struct represent the False value. I'll leave the details to you.
Little late to the game but, is there any reason your not using an enum?
after all if you just need a Trinary value then the struct is massive overkill
public enum Tribool{
Unknown =0,
True = -1,
False = 1
}

Need help understanding C# generics

I am self-studying a C# reference and it gives the following information:
1.21.4. Declaring Generic Parameters
Generic parameters can be introduced in the declaration of classes, structs, interfaces, delegates (see the upcoming "Delegates" section), and methods. Other constructs, such as properties, cannot introduce a generic parameter, but can use a generic parameter. For example, the property Value uses T:
public struct Nullable<T>
{
public T Value {get;}
}
First, I get an error trying to compile this saying that it must contain a body because it is neither abstract nor extern or that automatic parameters must have both get and set accessors.
Second, assuming it is wrong and I correct it by adding "set;", I cannot seem to format a call to it successfully.
That is just showing the API of Nullable<T> rather than the implementation. It's not meant to be compiled - System.Nullable<T> is part of the framework, you don't have to implement it yourself.
You appear to be reading "C# 3.0 in a Nutshell". Well, the example is just that - an example. It is only intended to illustrate how the Value property of the Generic Nullable class exposes the generic parameter declared by the containing type.
It isn't meant to be part of a compilable example.
I'm not sure if you just picked a bad example for your struct name (since Nullable is a framework struct), but if not, the error is due to the fact that you have no set accessor in your property. Automatic properties (added in C# 3.0) need both a get and set property. So, if you change the code to:
public struct Nullable<T>
{
public T Value {get; set; }
}
it should work. In this case, the error had nothing to do with generics. To create an instance, you could use:
Nullable<int> i = new Nullable<int>();
This will make it compile. However, as both Jon and Cerebrus has pointed out, it's probably just an example to show the workings of generics.
For an automatic property you always need both a getter and setter. Without a getter you could set the value, but nothing could ever retrieve it. Without a setter the value would always be the default because nothing could ever set it:
//tradition
private T _value;
public T Value
{
get
{
return _value;
}
}
//locally, _value can always be set
//Auto-matically implemented property
public T Value { get; }
//there is never a way to set it
//with this it can be privately set, but is get only to everyone else
public T Value{ get; private set; }
Your question here seems to be about auto-properties, rather than generics.
Auto-properties must have a set accessor, although it doesn't have to have the same visibility as the get:
public T Value { get; private set; }
You can call the set in the constructor:
public Nullable ( T value ) {
Value = value;
}
Although in this case you're dealing with a struct, and they always have a default (parameterless) constructor - you have to be a bit more careful with structs and auto-properties.
In .net there's already a nullable generic:
Nullable<int> i = GetCounterThatMightBeNull();
int j = 0;
if( i.HasValue )
j = i.Value;
...
This was added in .Net 2 (at the same time as generics), and while early betas looked like the code above they streamlined it the final version:
//int? is shorthand for Nullable<int>
int? i = GetCounterThatMightBeNull();
// ?? is shorthand for the null check
int j = i ?? 0;
//or
if( i == null ) {
//this works even though Nullable<int> is a struct
}

Categories