![](/img/trans.png)
[英]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.