Search code examples
c#referencestructvalue-typedefault-constructor

Is there a way I can prevent struct from being insantiated or can I have a class that will be copied?


Ok this is more curiosity than practical requirement.

Let's say I have this class:

public sealed class Entity
{
    int value;

    Entity()
    {

    }

    public static implicit operator Entity(int x)
    {
        return new Entity { value = x };
    }
}

I don't want this class to be instantiated outside the class and this works. But here Entitys will be referenced and not copied like value types. This class being so small I want it to behave likes value types. Also if I compare two instances of Entitys like e1 == e2 it's going to give reference equality (ok I can overload == but that's more work). So I would make it a struct:

public struct Entity
{
    int value;

    public static implicit operator Entity(int x)
    {
        return new Entity { value = x };
    }
}

But now someone can do new Entity() easily.

My question is there a way I can have a type (struct/class) that

1) will be copied every time the value is accessed, so that

Entity e1 = 1;
Entity e2 = e1;
ReferenceEquals(e1, e2); // prints false, just like any value type

2) has value semantics when comparing for equality

Entity e1 = 1;
Entity e2 = 1;
e1.Equals(e2); // prints true

// this is easy though by overriding default equality.

3) is not instantiable outside the scope of the type:

Entity e = new Entity(); // should not compile

Basically close to an enum's behaviour. I can certainly live without it, just learning.


Solution

  • Its not possible to do re-define or try to hide the default constructor for a struct in C# because the C# compiler routinely comples code based on the assumption that the parameterless constructor does nothing. See Why can't I define a default constructor for a struct in .NET?.

    Your options are either

    • Use a class
    • Ensure that the default value for your struct has some meaning (e.g. in your case the int will be initialised to 0) - this is what enums do (recall that enums are initialised to 0).

    My recommendation would be to use a class until you identify that there is a performance problem.