Gibt es einen generischen Konstruktor mit Parameterbeschränkung in C #?

In C # können Sie eine generische Methode wie folgt einschränken:

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

Wo Sie angeben, dass T einen Konstruktor haben sollte, der keine Parameter benötigt. Ich frage mich, ob es eine Möglichkeit gibt, eine Einschränkung wie ” gibt es einen Konstruktor mit einem float[,] Parameter?

Der folgende Code kompiliert nicht:

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

Eine Problemumgehung ist auch nützlich?

   

Wie Sie herausgefunden haben, können Sie das nicht tun.

Als Workaround stelle ich normalerweise einen Delegaten zur Verfügung, der Objekte vom Typ T erstellen kann:

 public class A { public static void Method (T a, Func creator) { //...do something... } } 

Es gibt kein solches Konstrukt. Sie können nur eine leere Konstruktoreinschränkung angeben.

Ich arbeite dieses Problem mit Lambda-Methoden ab.

 public static void Method(Func del) { var t = del(42); } 

Anwendungsfall

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

Wenn Sie mit reflection ein generisches Objekt erstellen, muss der Typ immer noch den korrekten Konstruktor deklariert haben oder es wird eine Ausnahme ausgetriggers. Sie können jedes Argument übergeben, solange sie mit einem der Konstruktoren übereinstimmen.

Auf diese Weise können Sie dem Konstruktor in der Vorlage keine Einschränkung auferlegen. Wenn der Konstruktor fehlt, muss eine Ausnahme zur Laufzeit behandelt werden, anstatt einen Fehler zur Kompilierzeit zu erhalten.

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

Hier ist ein Workaround dafür, den ich persönlich recht effektiv finde. Wenn Sie daran denken, was eine generische parametrisierte Constructor-Constraint ist, ist es wirklich eine Zuordnung zwischen Typen und Konstruktoren mit einer bestimmten Signatur. Sie können Ihr eigenes Mapping mit einem Wörterbuch erstellen. Fügen Sie diese in eine statische “Factory” -class ein, und Sie können Objekte unterschiedlichen Typs erstellen, ohne sich jedes Mal darum kümmern zu müssen, ein Konstruktor-Lambda zu erstellen:

 public static class BaseTypeFactory { private delegate BaseType BaseTypeConstructor(int pParam1, int pParam2); private static readonly Dictionary mTypeConstructors = new Dictionary { { typeof(Object1), (pParam1, pParam2) => new Object1(pParam1, pParam2) }, { typeof(Object2), (pParam1, pParam2) => new Object2(pParam1, pParam2) }, { typeof(Object3), (pParam1, pParam2) => new Object3(pParam1, pParam2) } }; 

dann in Ihrer generischen Methode, zum Beispiel:

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

Nein. Die einzige Constructor-Einschränkung, die Sie angeben können, ist momentan für einen Konstruktor ohne Argumente.

Ich denke, das ist die sauberste Lösung, die die Art und Weise, wie ein Objekt konstruiert wird, einschränkt. Es ist nicht vollständig Kompilierzeit überprüft. Wenn Sie die Übereinstimmung haben, dass der eigentliche Konstruktor der classn dieselbe Signatur wie die IConstructor-Schnittstelle hat, ist es so, als ob Sie eine Einschränkung für den Konstruktor haben. Die Constructor Methode ist ausgeblendet, wenn normal mit dem Objekt gearbeitet wird, aufgrund der expliziten Schnittstellenimplementierung.

 using System.Runtime.Serialization; namespace ConsoleApp4 { class Program { static void Main(string[] args) { var employeeWorker = new GenericWorker(); employeeWorker.DoWork(); } } public class GenericWorker 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; } } }