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
}
Related
int? num = null;
How does it work under the hood? I always assumed Nullable is a class and today I was debugging and was surprised to see it's a struct. I checked the source code and found this implicit operator:
[System.Runtime.Versioning.NonVersionable]
public static implicit operator Nullable<T>(T value)
{
return new Nullable<T>(value);
}
It's obviously not the answer here since null is not an int. In addition the constructor is this:
[System.Runtime.Versioning.NonVersionable]
public Nullable(T value)
{
this.value = value;
this.hasValue = true;
}
So the constructor is not called either.
Is compiler using some synthetic sugar here?
type? t = null;
is recognized by the compiler and replaced with type? t = new type?(), which invokes the default constructor which in turn sets the object to all zeros. The property HasValue is backed by a boolean variable such that false is the correct initial value in this case.
In just about every place, these constructions are treated as though they were references to a an object of type type. In order to observe they aren't you would need a mutable struct. The compiler knows about type? in quite a few ways including checking the HasValue property when boxing and boxing to a null or a boxed type. If you manage to get a boxed type? the unboxer should be able to handle it, but there doesn't seem to be a way to get a boxed type? anymore unless you're writing extern functions.
Nullable is an struct. And i know structs cant be assigned 'null'. So how could we assign Nullable's object a null? What is the reason?
It doesn't actually accept a value of null; it simply has syntactic sugar that allows it to act like it's null. The type actually looks a bit like this:
struct Nullable<T>
{
private bool hasValue;
private T value;
}
So when it's initialized hasValue == false, and value == default(T).
When you write code like
int? i = null;
The C# compiler is actually doing this behind the scenes:
Nullable<T> i = new Nullable<T>();
And similar checks are made when casting null to an int? at run-time as well.
Further Reading
Why can assign “null” to nullable types
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.
How can we implement a nullable type in C# if we didn't have this feature in C#?
Nullable Implementation for prior .NET 2.0
You can wrap a native type into a struct (quick example to give you an idea, untested, lots of room for improvement):
public struct NullableDouble {
public bool hasValue = false;
private double _value;
public double Value {
get {
if (hasValue)
return _value;
else
throw new Exception(...);
}
set {
hasValue = true;
_value = value;
}
}
}
Clearly, you won't get the syntactic sugar of newer C# versions, i.e. you have to use myNullableDouble.hasValue instead of myNullableDouble == null, etc. (See Andreas' comment.)
Nullable is a generic type. Without generics it is not possible to implement a nullable like that and wouldn't really make sense.
You can't, without attaching business rules to existing values in the data type. eg. int.MinValue can be used as a placeholder, but what if you need this value? If you have a rule where all values are positive, it could work, but not as "nullable".
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
}