44

Is it possible to hide the parameterless constructor from a user in C#?

I want to force them to always use the constructor with parameters

e.g. this Position struct

public struct Position
{
    private readonly int _xposn;
    private readonly int _yposn;
    
    public int Xposn
    {
        get { return _xposn; }
    }

    public int Yposn
    {
        get { return _yposn; }
    }

    public Position(int xposn, int yposn)
    {
        _xposn = xposn;
        _yposn = yposn;
    }        
}

I only want users to be able to new up a Position by specifying the x and y coordinates.

However, the parameterless constructor is ALWAYS available.

I cannot make it private. Or even define it as public.

I have read this: Why can't I define a default constructor for a struct in .NET?

but it doesn't really help.

If this is not possible - what is the best way to detect if the Position I am being passed has values?

Explicitly checking each property field? Is there a slicker way?

Pang
  • 9,564
  • 146
  • 81
  • 122
ChrisCa
  • 10,876
  • 22
  • 81
  • 118

4 Answers4

42

No, you can't do this. As you said, similar question has been asked before - and I thought the answer was fairly clear that you couldn't do it.

You can create a private parameterless constructor for a struct, but not in C#. However, even if you do that it doesn't really help - because you can easily work around it:

MyStruct[] tmp = new MyStruct[1];
MyStruct gotcha = tmp[0];

That will be the default value of MyStruct - the "all zeroes" value - without ever calling a constructor.

You could easily add a Validate method to your struct and call that each time you received one as a parameter, admittedly.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 13
    I see this as a usability issue more than anything else. The default constructor might make a _valid_ object, but for many structs it won't be what the user will want or expect. Nonetheless some people will use that default constructor just because it's the first option their IDE gives them. And then they'll have confusing bugs caused by zeroed-out structs that should have been filled with data, or they'll waste time trying to figure out why they can't set properties on an immutable struct. From an API-design perspective I wish it were possible to hide the default constructor. – MB. Oct 12 '11 at 16:29
  • 2
    +1 @MB. A private default constructor would help, even if a determined "fool" can work around it. As a C++ salt, I think of `private` as a hint to not shoot yourself in the foot, there is always a work-around using pointers. And array semantics can be taken care of by just not allowing arrays of such structs to be created. – Adrian Ratnapala Feb 27 '14 at 12:58
  • Hey Jon just one thing about parameterized constructors of struct. If you can validate it as I've read it somewhere. A parameterized constructor for a struct still calls default parameterless constructor (which his predefined for a struct in FCL) as first thing in its execution. I believe there is a compiler trick involved to achieve this behavior. – RBT Oct 19 '16 at 02:03
  • 1
    @RBT: There are changes in C# 6 around this in terms of whether you need to do so explicitly or not for automatically-implemented properties to work, but beyond that I don't think it's easily observable, unless you add a custom parameterless constructor via IL... my experience is that that isn't *always* called, but I suspect it's called from parameterized constructors... I'd have to check, but it's not something I've ever actually seen in real code anyway. – Jon Skeet Oct 19 '16 at 06:00
5

Nope can't hide it. Structs cannot redefine zero arg constructor, so therefore its visibility can't be redefined.

DavidN
  • 5,117
  • 2
  • 20
  • 15
  • 1
    Well, .NET allows you to provide a custom parameterless constructor - but you can't do it *directly* in C# and it doesn't help much anyway, as you can easily work around it. – Jon Skeet Feb 11 '09 at 07:35
3

Well a struct is literally a declaration of how the memory will sit.

Even when you use an object, the objects pointer IS declared, regardless of whether it's null.

The reason that you can't hide the constructor is because the struct demands that the CLR can create it as internally it must do this.

You could convert this struct into an object to achieve this task. Or use static analysis to ensure it's intialized before you use it?

struct point
{
   int xpos;
   int ypos;
}

Have a google for immutable objects, this appears to be what your after. I believe that they are looking to add this feature (but not in C# 4) to the language itself, because it is a common requirement. Is there a specific need for a struct here?

Spence
  • 28,526
  • 15
  • 68
  • 103
  • what do you mean by this? use static analysis to ensure it's intialized you mean check each field has a value? – ChrisCa Feb 11 '09 at 03:49
  • You can run a static analysis tool with a rule to ensure that any time someone uses the type in their code that the two values are intialized. or you could do some fancy footwork by declaring it as an object to do the check, and then change to a struct in the release build. – Spence Feb 11 '09 at 03:52
3

You cannot make a struct with a private parameter-less constructor or even declare a parameter-less constructor. You would have to change it to a class. Structs are not allow to declare a parameterless constructor.

From the Structs Tutorial on MSDN:

Structs can declare constructors, but they must take parameters. It is an error to declare a default (parameterless) constructor for a struct. Struct members cannot have initializers. A default constructor is always provided to initialize the struct members to their default values.

From the C# specification on MSDN:

11.3 Class and struct differences

Structs differ from classes in several important ways:

  • Structs are value types (Section 11.3.1).
  • All struct types implicitly inherit from the class System.ValueType (Section 11.3.2). Assignment to a variable of a struct type creates a copy of the value being assigned (Section 11.3.3).
  • The default value of a struct is the value produced by setting all value type fields to their default value and all reference type fields to null (Section 11.3.4). Boxing and unboxing operations are used to convert between a struct type and object (Section 11.3.5).
  • The meaning of this is different for structs (Section 11.3.6).
  • Instance field declarations for a struct are not permitted to include variable initializers (Section 11.3.7).
  • A struct is not permitted to declare a parameterless instance constructor (Section 11.3.8).
  • A struct is not permitted to declare a destructor (Section 11.3.9).
Ryan
  • 7,835
  • 2
  • 29
  • 36