[英]C# generic class type parameter and constraint that is the same as the generic parameter
[英]Is there a generic constructor with parameter constraint in C#?
在 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...
}
}
解決方法也有用嗎?
正如你所發現的,你不能這樣做。
作為一種解決方法,我通常提供一個可以創建T
類型對象的委托:
public class A {
public static void Method<T> (T a, Func<float[,], T> creator) {
//...do something...
}
}
使用反射創建泛型對象,該類型仍然需要聲明正確的構造函數,否則將引發異常。 您可以傳入任何參數,只要它們與構造函數之一匹配即可。
使用這種方式,您不能對模板中的構造函數施加約束。 如果缺少構造函數,則需要在運行時處理異常,而不是在編譯時出錯。
// 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);
沒有這樣的構造。 您只能指定一個空的構造函數約束。
我用 lambda 方法解決了這個問題。
public static void Method<T>(Func<int,T> del) {
var t = del(42);
}
用例
Method(x => new Foo(x));
這是我個人認為非常有效的解決方法。 如果您考慮什么是泛型參數化構造函數約束,它實際上是具有特定簽名的類型和構造函數之間的映射。 您可以使用字典創建自己的此類映射。 將它們放在靜態“工廠”類中,您可以創建不同類型的對象,而不必擔心每次都構建構造函數 lambda:
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 接口相同的簽名時,這有點像對構造函數施加約束。 由於顯式接口實現, 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;
}
}
}
如何創建帶有約束的泛型類,這里我選擇了 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);
這是 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(系統類型系統對象-)
Aaaa 和 C# 維護者的討論: https : //github.com/dotnet/csharplang/discussions/769
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.