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

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

public class A {

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

}

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

6 ответов


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

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

public class A {

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

}

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

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

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

Пример Использования

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

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

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

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

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

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

нет. На данный момент единственное ограничение конструктора можно указать для конструктора без аргументов.


Я думаю, что это самое чистое решение, которое ставит ограничение на Способ построения объекта. Это не полностью проверено время компиляции. Когда у вас есть согласие на то, чтобы фактический конструктор классов имел ту же подпись, что и интерфейс IConstructor, это похоже на ограничение на конструктор. The 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;
        }
    }
}