Is there a generic constructor with parameter constraint in C#?

Viewed 100251

In C# you can put a constraint on a generic method like:

public class A {

    public static void Method<T> (T a) where T : new() {
        //...do something...
    }

}

Where you specify that T should have a constructor that requires no parameters. I'm wondering whether there is a way to add a constraint like "there exists a constructor with a float[,] parameter?"

The following code doesn't compile:

public class A {

    public static void Method<T> (T a) where T : new(float[,] u) {
        //...do something...
    }

}

A workaround is also useful?

8 Answers

Using reflection to create a generic object, the type still needs the correct constructor declared or an exception will be thrown. You can pass in any argument as long as they match one of the constructors.

Used this way you cannot put a constraint on the constructor in the template. If the constructor is missing, an exception needs to be handled at run-time rather than getting an error at compile time.

// public static object CreateInstance(Type type, params object[] args);

// Example 1
T t = (T)Activator.CreateInstance(typeof(T));
// Example 2
T t = (T)Activator.CreateInstance(typeof(T), arg0, arg1, arg2, ...);
// Example 3
T t = (T)Activator.CreateInstance(typeof(T), (string)arg0, (int)arg1, (bool)arg2);

How about creating your generic class with constraints, here I chose struct and class to have value and reference types.

That way your constructor has a constraint on the values.

class MyGenericClass<T, X> where T :struct where X: class 
{
    private T genericMemberVariableT;
    private X genericMemberVariableX;
    public MyGenericClass(T valueT, X valueX)
    {
        genericMemberVariableT = valueT;
        genericMemberVariableX = valueX;
    }

    public T genericMethod(T genericParameter)
    {
        Console.WriteLine("Parameter type: {0}, value: {1}", typeof(T).ToString(), genericParameter);
        Console.WriteLine("Return type: {0}, value: {1}", typeof(T).ToString(), genericMemberVariableT);
        Console.WriteLine("Return type: {0}, value: {1}", typeof(X).ToString(), genericMemberVariableX);
        return genericMemberVariableT;
    }

    public T genericProperty { get; set; }
}

Implementation:

        MyGenericClass<int, string> intGenericClass = new MyGenericClass<int, string>(10, "Hello world");
        int val = intGenericClass.genericMethod(200);

Here's the recommended workaround by c# maintainers if you'd like to keep the constructor parameter-ful, call the constructor indirectly:

            i = (TService)Activator.CreateInstance(typeof(TService), new object[] {arg});

Where TService is a generic with a parameter-full constructor that I'd like to keep.

If you'd like to read up on how this method works: https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance?view=net-5.0#system-activator-createinstance(system-type-system-object-)

Aaaaand discussion by maintainers of C#: https://github.com/dotnet/csharplang/discussions/769

Related