[英]How can I constrain generic parameter to have a certain static function?
[英]How to constrain generic type to must have a construtor that takes certain parameters?
我有一個包裝通用類,打算與一組類型一起使用。 這些類型由實用程序生成,並且都派生自基類 ClientBase。 雖然 ClientBase 只有一個默認構造函數,但所有生成的類型都有默認構造函數,並且構造函數以字符串作為參數。 在包裝類的構造函數中,我使用接受字符串的構造函數實例化該類型的實例。 這是一個示例代碼:
public class ClientBase
{ }
public class GenericProxy<T>
where T: ClientBase, new()
{
T _proxy;
public GenericProxy(string configName)
{
_proxy = new T(configName);
}
}
此代碼無法編譯,因為不能保證類型 T 具有接受字符串的構造函數。 有沒有辦法在泛型類上定義約束來強制類型 T 必須有一個接受字符串的構造函數? 如果這是不可能的,那么處理這種情況的好方法是什么?
這是不可能的。 我希望看到“靜態接口”來處理這個問題,但不要指望他們很快......
備擇方案:
T
實現該接口)前兩個實際上是等價的。 基本上你會改變你的代理類是這樣的:
public class GenericProxy<T>
where T: ClientBase, new()
{
string _configName;
T _proxy;
Func<string, T> _factory;
public GenericProxy(Func<string, T> factory, string configName)
{
_configName = configName;
_factory = factory;
RefreshProxy();
}
void RefreshProxy() // As an example; suppose we need to do this later too
{
_proxy = _factory(_configName);
}
}
(我假設您稍后會想要創建更多實例 - 否則您最好將 T 的實例傳遞給構造函數。)
不幸的是,您嘗試做的事情是不可能的。
這並沒有回答您的實際問題,限制了一個方法,但為了完整起見,您可以使用反射在運行時完成您的要求:
private T Get<T>(string id)
{
var constructor = typeof(T).GetConstructor(new Type[] { typeof(X), typeof(Y) });
if (constructor == null) throw new InvalidOperationException("The type submitted, " + typeof(T).Name + ", does not support the expected constructor (X, Y).");
var data = GetData(id);
return (T)constructor.Invoke(new object[] { data.x, data.y });
}
正如 Jon 所指出的,對此沒有內置支持 - 但順便說一句,您可以使用Expression
為構造函數創建類型化委托(比反射更快)。 執行此操作的代碼可以在MiscUtil (在MiscUtil.Linq.Extensions.TypeExt
)中找到。
這是基於@JonSkeet 答案的完整工作示例:
using System;
using System.Collections.Generic;
namespace GenericProxy
{
class Program
{
static void Main()
{
GenericProxy<ClientBase> proxy = new GenericProxy<ClientBase>(ClientBase.Factory, "cream");
Console.WriteLine(proxy.Proxy.ConfigName); // test to see it working
}
}
public class ClientBase
{
static public ClientBase Factory(string configName)
{
return new ClientBase(configName);
}
// default constructor as required by new() constraint
public ClientBase() { }
// constructor that takes arguments
public ClientBase(string configName) { _configName = configName; }
// simple method to demonstrate working example
public string ConfigName
{
get { return "ice " + _configName; }
}
private string _configName;
}
public class GenericProxy<T>
where T : ClientBase, new()
{
public GenericProxy(Func<string, T> factory, string configName)
{
Proxy = factory(configName);
}
public T Proxy { get; private set; }
}
}
期望看到以下輸出: ice cream
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.