186

C#では、次のようなジェネリックメソッドに制約を課すことができます。

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

}

回避策も役立ちますか?

4

8 に答える 8

160

あなたが見つけたように、あなたはこれをすることはできません。

回避策として、私は通常、次のタイプのオブジェクトを作成できるデリゲートを提供しますT

public class A {

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

}
于 2009-12-05T17:41:00.153 に答える
55

リフレクションを使用してジェネリックオブジェクトを作成する場合でも、型には正しいコンストラクターを宣言する必要があります。そうしないと、例外がスローされます。コンストラクターの1つと一致する限り、任意の引数を渡すことができます。

このように使用すると、テンプレートのコンストラクターに制約を課すことはできません。コンストラクターが欠落している場合は、コンパイル時にエラーが発生するのではなく、実行時に例外を処理する必要があります。

// 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);
于 2012-03-26T08:13:13.080 に答える
47

そのような構成はありません。空のコンストラクター制約のみを指定できます。

私はラムダメソッドでこの問題を回避します。

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

使用事例

Method(x => new Foo(x));
于 2009-12-05T17:40:09.203 に答える
18

これは、私が個人的に非常に効果的だと思う回避策です。一般的なパラメーター化されたコンストラクター制約とは何かを考えると、それは実際には、特定のシグニチャーを持つ型とコンストラクターの間のマッピングです。辞書を使用して、このような独自のマッピングを作成できます。これらを静的な「ファクトリ」クラスに入れると、毎回コンストラクタラムダを構築することを心配することなく、さまざまなタイプのオブジェクトを作成できます。

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;
   }
于 2012-02-08T07:48:03.177 に答える
8

いいえ。現時点で指定できるコンストラクター制約は、引数なしのコンストラクターのみです。

于 2009-12-05T17:39:22.200 に答える
7

これは、オブジェクトの構築方法に制約を課す最もクリーンなソリューションだと思います。コンパイル時に完全にチェックされるわけではありません。クラスの実際のコンストラクターが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;
        }
    }
}
于 2018-04-05T14:19:46.413 に答える
3

制約付きのジェネリッククラスを作成するのはどうですか。ここでは、値型と参照型を持つ構造体とクラスを選択しました。

そうすれば、コンストラクターは値に制約を持ちます。

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);
于 2019-04-03T16:54:25.650 に答える
2

コンストラクターをパラメーターフルに保ちたい場合は、c#メンテナーが推奨する回避策を次に示します。コンストラクターを間接的に呼び出します。

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

ここで、TServiceは、保持したいパラメーターがいっぱいのコンストラクターを持つジェネリックです。

このメソッドがどのように機能するかを知りたい場合は、 https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance?view = net-5.0#system-activator-createinstance( system-type-system-object-)

AaaaとC#のメンテナによるディスカッション: https ://github.com/dotnet/csharplang/discussions/769

于 2021-07-09T23:20:05.693 に答える