How to constrain generic type to must have a construtor that takes certain parameters?

做~自己de王妃 提交于 2019-11-27 13:37:56

It's not possible. I'd like to see "static interfaces" to handle this, but don't expect them any time soon...

Alternatives:

  • Specify a delegate to act as a factory for T
  • Specify another interface to act as a factory for T
  • Specify an interface on T itself for initialization (and add a constraint so that T implements the interface)

The first two are really equivalent. Basically you'd change your proxy class to something like this:

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);
    }
}

(I assume you're going to want to create more instances later - otherwise you might as well pass an instance of T into the constructor.)

Unfortunately what you're trying to do isn't possible.

MSDN article on Type Constraints

This does not answer your actual question, constraining a method, but for completeness here's how you can do what you're asking at run time, using reflection:

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 });
    }

As Jon notes, there is no inbuilt support for this - but as an aside you can create a typed delegate to the constructor (faster than reflection) using Expression. The code to do this can be found in MiscUtil (in MiscUtil.Linq.Extensions.TypeExt).

Here is a full working example based on @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; }
    }
}

Expect to see the following output: ice cream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!