Reputation: 11006
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?
Upvotes: 50
Views: 19868
Reputation: 8005
Is it possible to hide the parameterless constructor from a user in C#?
No, 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.
What is the best way to detect if the Position I am being passed has values?
One option to detect if a struct has values is to create an Empty
instance and an IsEmpty
method/property, similar to my answer here. Here are some examples:
// System.Guid
public struct Guid : IFormattable, IComparable, IComparable<Guid>, IEquatable<Guid>
{
public static readonly Guid Empty;
//...
}
// System.Drawing.Point
public struct Point
{
public static readonly Point Empty;
public bool IsEmpty { get; }
//...
}
// From your question above:
public struct Position
{
public static readonly Position Empty = new Position();
public bool IsEmpty => _xposn == 0 && _yposn == 0;
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;
}
}
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:
Upvotes: 5
Reputation: 1501113
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.
Upvotes: 46
Reputation: 5197
Nope can't hide it. Structs cannot redefine zero arg constructor, so therefore its visibility can't be redefined.
Upvotes: 6
Reputation: 29342
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?
Upvotes: 4