Существует ли общий конструктор с ограничением параметра в С#?

В С# вы можете установить ограничение на общий метод, например:

public class A {

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

}

Если вы укажете, что T должен иметь конструктор, который не требует параметров. Мне интересно, есть ли способ добавить ограничение типа "существует конструктор с параметром float[,]?"

Следующий код не компилируется:

public class A {

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

}

Обходной путь также полезен?

Ответ 1

Как вы нашли, вы не можете этого сделать.

В качестве обходного пути я обычно предоставляю делегат, который может создавать объекты типа T:

public class A {

    public static void Method<T> (T a, Func<float[,], T> creator) {
        //...do something...
    }

}

Ответ 2

Нет такой конструкции. Вы можете указать только ограничение пустого конструктора.

Я работаю над этой проблемой с методами лямбда.

public static void Method<T>(Func<int,T> del) {
  var t = del(42);
}

Использование случая

Method(x => new Foo(x));

Ответ 3

Используя отражение для создания универсального объекта, типу все еще нужен объявленный конструктор или исключение. Вы можете передать любой аргумент, если они соответствуют одному из конструкторов.

Используется таким образом, чтобы вы не могли установить ограничение на конструктор в шаблоне. Если конструктор отсутствует, исключение должно обрабатываться во время выполнения, а не получать ошибку во время компиляции.

// 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);

Ответ 4

Вот обходной путь для этого, который я лично считаю весьма эффективным. Если вы думаете о том, что является общим параметрическим ограничением конструктора, это действительно сопоставление между типами и конструкторами с определенной сигнатурой. Вы можете создать свое собственное сопоставление с помощью словаря. Поместите их в статический класс factory ", и вы можете создавать объекты различного типа, не беспокоясь о том, чтобы каждый раз создавать конструктор лямбда:

public static class BaseTypeFactory
{
   private delegate BaseType BaseTypeConstructor(int pParam1, int pParam2);

   private static readonly Dictionary<Type, BaseTypeConstructor>
   mTypeConstructors = new Dictionary<Type, BaseTypeConstructor>
   {
      { typeof(Object1), (pParam1, pParam2) => new Object1(pParam1, pParam2) },
      { typeof(Object2), (pParam1, pParam2) => new Object2(pParam1, pParam2) },
      { typeof(Object3), (pParam1, pParam2) => new Object3(pParam1, pParam2) }
   };

то в вашем общем методе, например:

   public static T BuildBaseType<T>(...)
      where T : BaseType
   {
      ...
      T myObject = (T)mTypeConstructors[typeof(T)](value1, value2);
      ...
      return myObject;
   }

Ответ 5

Нет. На данный момент единственное ограничение конструктора, которое вы можете указать, это конструктор no-arg.

Ответ 6

Я думаю, что это самое чистое решение, которое как бы накладывает ограничения на способ создания объекта. Это не полностью проверено время компиляции. Когда у вас есть соглашение, чтобы фактический конструктор классов имел ту же сигнатуру, что и интерфейс IConstructor, это все равно, что иметь ограничение на конструктор. Метод Constructor скрыт при нормальной работе с объектом из-за явной реализации интерфейса.

using System.Runtime.Serialization;

namespace ConsoleApp4
{
    class Program
    {
        static void Main(string[] args)
        {
            var employeeWorker = new GenericWorker<Employee>();
            employeeWorker.DoWork();
        }
    }

    public class GenericWorker<T> where T:IConstructor
    {
        public void DoWork()
        {
            T employee = (T)FormatterServices.GetUninitializedObject(typeof(T));
            employee.Constructor("John Doe", 105);
        }
    }

    public interface IConstructor
    {
        void Constructor(string name, int age);
    }

    public class Employee : IConstructor
    {
        public string Name { get; private set; }
        public int Age { get; private set; }

        public Employee(string name, int age)
        {
            ((IConstructor)this).Constructor(name, age);
        }

        void IConstructor.Constructor(string name, int age)
        {
            Name = name;
            Age = age;
        }
    }
}

Ответ 7

Как насчет создания вашего универсального класса с ограничениями, здесь я выбрал struct и class, чтобы иметь значения и ссылочные типы.

Таким образом, ваш конструктор имеет ограничение на значения.

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; }
}

Реализация:

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