Home > Back-end >  Which Constructor takes precedence when there are two matches for a Generic Class's Constructor
Which Constructor takes precedence when there are two matches for a Generic Class's Constructor

Time:08-24

What determines which constructor is used if a Generic class has 2 constructors: One takes (T data), and another (string errorMessage).

And an instance is created with type string?

For me it seems to be using the constructor with parameter (string errorMessage) instead of (T data).

  • I'm wondering why?
  • And is there a way to make it use the generic (T data) constructor instead?

Luckily I don't need to in my case, but I don't know how I would.

public class GenericClass<T>
{
    public T Data { get; set; }
    public string ErrorMessage { get; set; }

    public GenericClass(T data)
    {
        Data = data;
    }

    public GenericClass(string errorMessage)
    {
        ErrorMessage = errorMessage;
    }
}

New instance is created with either:

new GenericClass<string>("some error");

Or:

new GenericClass<string>("some data");

I thought it would give an Ambiguous Constructor error, but it doesn't. It always uses the (string errorMessage) constructor.

CodePudding user response:

Your problem is not specific to constructors. The same behaviour can be observed in case of method overloading. For example:

public class ClassA
{
    public static void MethodA<T>(T data)
    {
        Console.WriteLine("Generic version has been called");
    }

    public static void MethodA(string errorMessage)
    {
        Console.WriteLine("String version has been called");
    }
}

The related documentation can be found here: Overload resolution.


You can enforce the call of the other constructor if you are taking advantage of named parameters feature of C#:

new GenericClass<string>(data: "some data");

Of course this technique works only if the parameter names are different.
So, this won't work if you would define your class like this:

public class GenericClass<T>
{
    public T Data { get; set; }
    public string ErrorMessage { get; set; }

    public GenericClass(T _)
      => Data = _;

    public GenericClass(string _)
      => ErrorMessage = _;
}

A solution could be for this problem

  • introduce factory methods
  • change the properties' set to init
  • and create a private ctor
public class GenericClass<T>
{
    public T Data { get; init; }
    public string ErrorMessage { get; init; }

    public static GenericClass<T> CreateWithData(T _)
      => new GenericClass<T> { Data = _ };
     
    public static GenericClass<string> CreateWithError(string _)
      => new GenericClass<string> { ErrorMessage = _ };
     
    private GenericClass() {}
}
  • Related