2
votes

Recently a compiler warning and (very useful) hint prompted me to write the code below.

I had no idea you could do this, but it is perfectly legal, and also convenient in that I can declare a managed struct with public properties similar to public fields of an unmanaged struct, and also initialize it with an object instead of having to pass all the fields as parameters.

What confuses me is that this appears to call the explicit parameterless constructor, which would of course be illegal for this struct.

What's going on here, and has this syntax always been supported?

internal struct IconEntry
{
    public byte Width { get; set; }
    public byte Height { get; set; }
    public byte ColorCount { get; set; }
    public byte Reserved { get; set; }
    public short Planes { get; set; }
    public short BitCount { get; set; }
    public int BytesInRes { get; set; }
    public int ImageOffset { get; set; }

    public IconEntry(BinaryReader reader)
        : this()
    {
        Width = reader.ReadByte();
        Height = reader.ReadByte();
        ColorCount = reader.ReadByte();
        Reserved = reader.ReadByte();
        Planes = reader.ReadInt16();
        BitCount = reader.ReadInt16();
        BytesInRes = reader.ReadInt32();
        ImageOffset = reader.ReadInt32();
    }
}
4
<insert the obligatory "mutable structs are evil" comment here>Adam Houldsworth

4 Answers

3
votes

A struct always has a public parameterless constructor which can't be overriden: http://msdn.microsoft.com/en-us/library/aa288208%28v=vs.71%29.aspx

This means that a user still would be able to create an instance of this struct that is not initialized according to your logic but with default values for all properties:

var s = new IconEntry();
2
votes

All structs have a parameterless constructor - it's just implicit (e.g. it always exists with a default routine - one that sets all values to 0) - you just can't have an explicit one (e.g. one that you define yourself in code).

0
votes

Is there any reason you're exposing properties rather than fields for your struct? If the semantics of your data type imply that

  1. The entire state of an instance will be fully defined by the values exposed by some public members, such that two instances for whom all those report or contain identical values will be considered identical.
  2. Instances of the struct with any combination of values for the aforementioned members may be created easily, given the desired values in question.

that sounds like a perfect fit for a PODS (Plain Old Data Struct). Exposed fields are more efficient and less quirky than struct properties. Given that all struct types always expose all fields for mutation or capture by struct assignment, the encapsulation offered by struct properties is of extremely limited value.

The way you have your constructor written, your struct will have all fields set to all-bits-zero, and then be passed repeatedly to methods which will update one field at a time with the desired value. The fact that the struct is specified as initialized to all-bits-zero by the this will make the compiler happy, but using many individual properties to set up fields piecemeal is inefficient.

Incidentally, even better than a constructor in many cases would be a static method which simply takes your struct as a ref parameter. In many cases, using a constructor with a struct will result in an unnecessary copy operation which could be avoided by using a static method with a ref parameter.

0
votes

Since structs are value types, it's data members should be initialized if you are explicitly invoke the constructor. And mention "this()" to intimate compiler to complete the assignment of auto implemented properties if anything you mentioned.

struct Student
{        
    string _sname;       

    public int ID
    {
        get; set;
    }

    internal Student(string sname):this()
    {            
        _sname = sname;
    }

    internal void PrintDetails()
    {
        Console.WriteLine("ID : {0} Name: {1}", ID, _sname);
    }
}

Main method:

class Program
     {
         static void Main()
         {
             Student st = new Student("John")
             {
                 ID=101
             };

             st.PrintDetails(); 

         } 
     }

Output:
ID : 101 Name: John

If you are not mention "this()", compiler forcefully ask you to complete the full assignment of ID property.

If you are not explicitly invoke the constructor, compiler implicitly set default values for the struct data members.