C# 如何将泛型类型约束为必须具有接受特定参数的构造函数?

C# 如何将泛型类型约束为必须具有接受特定参数的构造函数?,c#,generics,constraints,C#,Generics,Constraints,我有一个包装器泛型类,打算与一组类型一起使用。这些类型由实用程序生成,并且都是从基类ClientBase派生的。虽然ClientBase只有一个默认构造函数,但所有生成的类型都有默认构造函数,并且构造函数以字符串作为参数。在包装类的构造函数中,我用接受字符串的构造函数实例化了该类型的实例。下面是一个示例代码: public class ClientBase { } public class GenericProxy<T> where T: ClientBase, new()

我有一个包装器泛型类,打算与一组类型一起使用。这些类型由实用程序生成,并且都是从基类ClientBase派生的。虽然ClientBase只有一个默认构造函数,但所有生成的类型都有默认构造函数,并且构造函数以字符串作为参数。在包装类的构造函数中,我用接受字符串的构造函数实例化了该类型的实例。下面是一个示例代码:

public class ClientBase
{ }

public class GenericProxy<T>
    where T: ClientBase, new()
{
    T _proxy;

    public GenericProxy(string configName)
    {
        _proxy = new T(configName);    
    }
}
公共类ClientBase
{ }
公共类泛型代理
其中T:ClientBase,new()
{
T_代理;
公共GenericProxy(字符串configName)
{
_proxy=newt(configName);
}
}

这段代码不会编译,因为类型T不能保证有一个接受字符串的构造函数。有没有一种方法可以在泛型类上定义一个约束来强制类型T必须有一个接受字符串的构造函数?如果这是不可能的,有什么好的选择来处理这种情况

不幸的是,你想做的是不可能的


这是不可能的。我希望能处理好这件事,但别指望他们会很快

备选方案:

  • 指定一个代理作为T的工厂
  • 指定另一个接口作为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);
    }
}
公共类GenericProxy
其中T:ClientBase,new()
{
字符串_configName;
T_代理;
Func_工厂;
公共GenericProxy(Func工厂,字符串configName)
{
_configName=configName;
_工厂=工厂;
RefreshProxy();
}
void RefreshProxy()//作为示例;假设我们以后也需要这样做
{
_代理=\工厂(\配置名称);
}
}

(我假设您以后会想创建更多实例-否则您可能会将T的实例传递到构造函数中。)

正如Jon所指出的,这没有内置的支持-但作为一种补充,您可以使用
表达式创建构造函数的类型化委托(比反射更快)。执行此操作的代码可以在中找到(在
MiscUtil.Linq.Extensions.TypeExt
)。

这并不能回答您的实际问题,限制了一个方法,但为了完整性,下面介绍了如何使用反射在运行时执行您要求的操作:

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 });
    }
private T Get(字符串id)
{
var constructor=typeof(T).GetConstructor(新类型[]{typeof(X),typeof(Y)});
if(constructor==null)抛出新的invalidoOperationException(“提交的类型,“+typeof(T).Name+”,不支持预期的构造函数(X,Y)”;
var data=GetData(id);
return(T)constructor.Invoke(新对象[]{data.x,data.y});
}

以下是一个基于@JonSkeet answer的完整工作示例:

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; }
    }
}
使用系统;
使用System.Collections.Generic;
命名空间泛型代理
{
班级计划
{
静态void Main()
{
GenericProxy代理=新的GenericProxy(ClientBase.Factory,“cream”);
Console.WriteLine(proxy.proxy.ConfigName);//测试它是否工作
}
}
公共类客户端库
{
静态公共ClientBase工厂(字符串configName)
{
返回新的ClientBase(configName);
}
//new()约束所需的默认构造函数
公共ClientBase(){}
//接受参数的构造函数
公共ClientBase(字符串configName){u configName=configName;}
//演示工作示例的简单方法
公共字符串配置名称
{
获取{return“ice”+\u configName;}
}
私有字符串_configName;
}
公共类泛型代理
其中T:ClientBase,new()
{
公共GenericProxy(Func工厂,字符串configName)
{
代理=工厂(配置名称);
}
公共T代理{get;私有集;}
}
}
希望看到以下输出:
冰淇淋