17

Is it possible to set or override the default state for a structure?

As an example I have an

enum something{a,b,c,d,e};

and a structure that links 2 values for that enum

struct SomethingData
{
    something type;
    int Value;
    double Multipler;

    SomethingData(something enumVal, int intVal, double DblVal) {...}
}

But can I specify that the default state is

SomethingData(something.c,0,1);

12 Answers12

13

Struct constructors are similar to class constructors, except for the following differences:

Structs cannot contain explicit parameterless constructors. Struct members are automatically initialized to their default values. A struct cannot have an initializer in the form: base (argument-list).

http://msdn.microsoft.com/en-us/library/aa288208(v=vs.71).aspx

So, short answer, no you can't override the default constructor (every struct has a parameterless constructor and you can't hide it or override it)...

Jorge Córdoba
  • 51,063
  • 11
  • 80
  • 130
  • how about a work around that lets you specify what the default values are? the best i can come up with is creating a constant instance of the structure in the structure and then setting the value to this instead of calling the default constructor –  Dec 21 '10 at 17:23
  • @Mike: You could do that. But this will not hide or eliminate the type's default constructor. (Note that you'll have to use a `static readonly` field for this instead of a `const`, since fields of a struct type cannot be made constant.) – cdhowie Dec 21 '10 at 17:24
  • It's a shame though, especially when you declare an array of some struct, and wanted a particular struct member to have a particular default value ... you have to loop through the array and set it. (For example, I ported an algorithm from C which gave special meaning to '-1'). But although it's more code, perhaps we don't end up doing any more *work* than if we were permitted to specify alternative defaults? – David Bullock Apr 30 '14 at 02:31
  • 1
    How about creating a static property `Default` that creates your default object? Instead of calling `new Foo()`, you'd call `Foo.Default`. This holds the default values in a central place and provides the minimal amount of extra code. – Didii Jul 19 '17 at 12:46
8

You can't. Structs always have a default constructor that sets every member to its default value (null for reference types, 0 for numeric types, false for bools, etc.) This behavior cannot be changed.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • What about for Enumerations? – Krythic Apr 07 '17 at 21:23
  • Edit, just checked. Enums default to the first index of the enumeration. This is actually extremely powerful, especially if the first index is declared as "None". – Krythic Apr 07 '17 at 21:25
  • @Krythic They will actually default to whatever enumeration member has the value 0, which will indeed be the first one if you don't explicitly assign values. But if you do something like `enum Foo { A = 1, B = 0 }` then you will find that `default(Foo) == Foo.B` instead. If your enumeration doesn't have a member with the value 0, then the default value *won't be one of your enum options at all.* – cdhowie Apr 08 '17 at 17:57
1

Creating a class object will cause all of the instance fields to come into existence before anything--even the class constructor--can access it, and allocating an array will cause all of its elements to exist before anything can access the array. Both of these actions will cause all of the memory allocated to those fields or elements to be zeroed out without regard for the data types to be stored therein.

When a class-type storage location comes into existence, it will initially hold a null reference. When a structure-type storage location comes into existence, all of its fields (and any fields of structures within it) will do so simultaneously. Unlike class object instances which can only come into existence by using a constructor, structure-type storage locations are brought into existence without using any of the structure's own code. Consequently, the structure's definition will have no say in what should happen when "instances" [i.e. struct-type storage locations] come into existence.

A struct is, fundamentally, a collection of fields bound together with duct tape. If a struct is supposed to behave like something else, it should typically make its fields private and pretend to be immutable [even though struct assignment actually mutates the destination struct by overwriting all its fields with the corresponding values from the source, and the struct definition gets no say in the matter]. If, however, a struct is supposed to encapsulate a fixed set of related but independent values (e.g. the coordinates of a point), which may independently accommodate any combination of values which are legal for their respective types, a struct should simply expose its fields publicly. Some people may whine about "mutable structs are evil", but the evils only apply when invoking self-mutating methods on a struct. Structs which expose their state as fields behave like collections of variables stuck together with duct tape. If what one needs is a collection of variables stuck together with duct tape, trying to make a struct pretend to be immutable will simply make it harder to program with.

supercat
  • 77,689
  • 9
  • 166
  • 211
1

There is a workaround to make this happen by using custom Property getters. Observe:

public struct Foostruct
{
    private int? _x;
    private int? _y;

    public int X
    {
        get { return _x ?? 20; } // replace 20 with desired default value
        set { _x = value; }
    }

    public int Y
    {
        get { return _y ?? 10; } // replace 10 with desired default value
        set { _y = value; }
    }
}

This will only work for value types (which can be wrapped with nullable) but you could potentially do something similar for reference types by wrapping them in a generic class like below:

public class Wrapper<TValue>
{
    public TValue Value { get; set; }
}

public struct Foostruct
{
    private Wrapper<Tick> _tick;

    public Tick Tick
    {
        get { return _tick == null ? new Tick(20) : _tick.Value; }
        set { _tick = new Wrapper<Tick> { Value = value }; }
    }
}
Sellorio
  • 1,806
  • 1
  • 16
  • 32
1

You can't override the default (parameterless) constructor for a struct. You can only add new constructors, which take parameters.

http://csharp.2000things.com/2010/10/03/108-defining-a-constructor-for-a-struct/

Sean Sexton
  • 1,069
  • 2
  • 11
  • 19
0

Each time you get/set property you need to set default value call InitDefaultValues() method

private string _numberDecimalSeparator;
public string NumberDecimalSeparator
{
    get
    {
        InitDefaultValues();
        return _numberDecimalSeparator;
    }
    set
    {
        InitDefaultValues(); 
        _numberDecimalSeparator = value;
    }
}

...

private void InitDefaultValues()
{
    if (!_inited)
    {
        _inited = false;
        var ci = CultureInfo.CurrentCulture;
         _numberDecimalSeparator = ci.With(x => x.NumberFormat).Return(x => x.NumberDecimalSeparator, ".");

        ...
    }
}
Berezh
  • 942
  • 9
  • 12
  • Structures should not mutate themselves in property getters. If `MyObject.Foo` is a field whose underlying type is your structure type, then reading `MyObject.Foo.NumberDecimalSeparator` will capture the current culture; if it's a property of that type, then reading `MyObject.Foo.NumberDecimalSeparator` will create a temporary copy of the underlying structure, capture the current culture into that copy, compute the return value of `NumberDecimalSeparator`, and abandon the temporary structure. – supercat Jun 09 '13 at 18:20
0

Kinda dumb, but works

public readonly static float default_value = 1;
public struct YourStruct{

    public float yourValue{
        get {
            return _yourValue + default_value;
        }
        set {
            _yourValue= value - default_value;
        }
    }
    public float _yourValue;
}
Guedez
  • 189
  • 3
  • 14
0

My solution. It works as well.

public struct DisplayOptions
{
    public bool isUpon;
    public bool screenFade;

    public static DisplayOptions Build()
    {
        // Return default value
        return new DisplayOptions(true, true);
    }

    DisplayOptions(bool isUpon, bool screenFade)
    {
        this.isUpon = isUpon;
        this.screenFade = screenFade;
    }

    public DisplayOptions SetUpon(bool upon)
    {
        this.isUpon = upon;
        return this;
    }

    public DisplayOptions SetScreenFade(bool screenFade)
    {
        this.screenFade = screenFade;
        return this;
    }
}

Use default value

        // Use default
        UIMaster.Instance.StartScreen("Screen 2", DisplayOptions.Build());
        // Use custome
        UIMaster.Instance.StartScreen("Screen 2", DisplayOptions.Build().SetScreenFade(false));
        UIMaster.Instance.StartScreen("Screen 2", DisplayOptions.Build().SetUpon(false));
Leo Nguyen
  • 614
  • 1
  • 9
  • 23
0

Somewhat related: I've often wanted to use the new object initializer syntax with an immutable value type. However, given the nature of a typical immutable value type implementation, there is no way to utilize that syntax, since the properties are read-only.

I've come up with this approach; In my opinion this still satisfies the immutability of the value type, but allows the code that is responsible for instantiating the value type greater control over the initialization of the internal data.

struct ImmutableValueType
{
    private int _ID;
    private string _Name;

    public int ID
    {
        get { return _ID; }
    }

    public string Name
    {
        get { return _Name; }
    }

    // Infuser struct defined within the ImmutableValueType struct so that it has access to private fields
    public struct Infuser
    {
        private ImmutableValueType _Item;

        // write-only properties provide the complement to the read-only properties of the immutable value type
        public int ID
        {
            set { _Item._ID = value; }
        }

        public string Name
        {
            set { _Item._Name = value; }
        }

        public ImmutableValueType Produce()
        {
            return this._Item;
        }

        public void Reset(ImmutableValueType item)
        {
            this._Item = item;
        }

        public void Reset()
        {
            this._Item = new ImmutableValueType();
        }

        public static implicit operator ImmutableValueType(Infuser infuser)
        {
            return infuser.Produce();
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        // use of object initializer syntax made possible by the Infuser type
        var item = new ImmutableValueType.Infuser
        {
            ID = 123,
            Name = "ABC",
        }.Produce();

        Console.WriteLine("ID={0}, Name={1}", item.ID, item.Name);
    }
}
Dr. Wily's Apprentice
  • 10,212
  • 1
  • 25
  • 27
  • Doesn't this make ImmutableValueType a mutable type? (since it can be modified via the Infuser type) I think this is what constructors are for – kelloti Dec 30 '10 at 19:10
  • It can be messy/tedious to write several constructor overloads to accommodate every possible way to initialize an object. Regarding the immutability: as I mentioned, in my opinion the immutability is maintained. You cannot get a reference to the "immutable" object without calling the infuser's Produce method (ok, I did add an implicit conversion operator, so it's your call whether to remove that). Once the value has been returned from the infuser's Produce method, the infuser can no longer manipulate that value, since in this case it is a value-type. – Dr. Wily's Apprentice Dec 30 '10 at 19:16
-1

this should work

public struct MyStruct 
{
    private string myName;
    private int? myNumber;
    private bool? myBoolean;
    private MyRefType myType;

    public string MyName
    {
        get { return myName ?? "Default name"; }
        set { myName= value; }
    }
    public int MyNumber
    {
        get { return myNumber ?? 42; }
        set { myNumber = value; }
    }
    public bool MyBoolean
    {
        get { return myBoolean ?? true; }
        set { myBoolean = value; }
    }
    public MyRefType MyType 
    {
        get { return myType ?? new MyRefType(); }
        set { myType = value; }
    }

    //optional
    public MyStruct(string myName = "Default name", int myNumber = 42, bool myBoolean = true)
    {
        this.myType = new MyRefType();
        this.myName = myName;
        this.myNumber = myNumber;
        this.myBoolean = myBoolean;
    }
}

[TestClass]
public class MyStructTest
{
    [TestMethod]
    public void TestMyStruct()
    {
        var myStruct = default(MyStruct);
        Assert.AreEqual("Default name", myStruct.MyName);
        Assert.AreEqual(42, myStruct.MyNumber);
        Assert.AreEqual(true, myStruct.MyBoolean);
        Assert.IsNotNull(myStruct.MyType);
    }
}
Minh Nguyen
  • 179
  • 3
  • 16
  • If you explicitly pass `null` for `myName` you end up with the default value, which shouldn't happen. If you assign `null` to `MyType`, same problem. You also shouldn't have a mutable reference type. They're evil. Finally, having properties is actually an important semantic difference from having fields, as is in the OP, specifically when it comes to dealing with mutable reference types (which is one reason why they're so evil). – Servy May 02 '14 at 20:37
  • @Servy what if I remove `MyType` and `MyName` and only use value types within the struct? is that still incorrect? My objective is to have a struct `MyConfig` that contains a few `bool` that defaults to true so I can use it as a default param like so: `public void MyMethod(MyConfig config = default(MyConfig)) { //... }` Thanks. – Minh Nguyen May 02 '14 at 20:56
  • It's still changing the semantics of the structure by changing fields to properties, yes. If it were immutable that probably wouldn't be a problem. – Servy May 02 '14 at 20:57
-1

This may work...

    public struct MyStruct
    {
        private bool _name;
        public string myName
        {
            get { return (_name ? myName : "Default name"); }
            set { _name = true; myName = value; }
        }
        private bool _num;
        public int myNumber 
        {
            get { return (_num ? myNumber : 42); }
            set { _num = true; myNumber = value; }
        }
        private bool _bool;
        public bool myBoolean
        {
            get { return (_bool ? myBoolean : true); }
            set { _bool = true; myBoolean = value; }
        }
        private bool _type;
        public MyRefType myType
        {
            get { return _type ? myType : new MyRefType(); }
            set { _type = true; myType = value; }
        }
    }

Nevermind StackOverflowException

KMier
  • 81
  • 1
  • 3
  • 1
    I figured that the bool associated with each variable would initialize to false then change to true when the value was changed outside of constructor. – KMier Oct 28 '14 at 19:54
-3

There is a workaround

public struct MyStruct
{
    public MyStruct(int h = 1, int l = 1)
    {
        high = h;
        low = l;
    }
    public int high;
    public int low;
}
Eugenio Miró
  • 2,398
  • 2
  • 28
  • 38
  • Clever idea, but this does not work -- did you try it? Calling `new MyStruct()` still yields an object with `high` and `low` set to 0. – cdhowie May 24 '13 at 14:41
  • You're right @cdhowie, I just tested compilation. At least it states that doesn't work so none else will try it hahaha. – Eugenio Miró May 25 '13 at 12:25