在运行时添加通用约束?

时间:2014-02-09 21:21:22

标签: c# generics constraints

如果有人有任何想法,我很难过。我有通用方法

public void Foo<TClass>(TClass item) where TClass : class
{ }

我想从另一个泛型方法调用此方法,但是这个泛型方法没有类型约束“where TClass:class”

public void Bar<T>(T item)
{
    this.Foo<T>(item);
} 

这不起作用,我收到错误

“类型'T'必须是引用类型才能将其用作参数'TClass'”

我理解。但我的问题是 - 我可以用C#语法做什么来“过滤”泛型类型“T”,如果它是一个类,则将它传递给“this.Bar”。像......那样......

public void Bar<T>(T item)
{
    if (typeof(T).IsClass)
        this.Foo<T **as class**>();
} 

我意识到我可以使用反射来调用Foo,但这似乎就像是作弊。我可以用C#在运行时使用约束传递“T”吗?

另外 - 我无法更改方法“Bar”的约束,因为它来自一个接口,所以约束必须匹配接口上的约束

4 个答案:

答案 0 :(得分:4)

不幸的是,如果不将Bar更改为具有通用约束class或使用反射,则无法执行此操作。为了编译C#,必须在编译时知道T确实是class值。无法使用typeof(T).IsClass之类的动态测试来满足此编译时约束。

你在问题​​中提到你不能改变Bar,但似乎你愿意接受动态失败的可能性。也许改为将Foo更改为没有约束,而是在T不是类类型时抛出异常

答案 1 :(得分:4)

在没有反射的情况下调用Foo的唯一方法是将item强制转换为其层次结构中的某个类型/类(在正确的IsClass检查之后)。

显然,在层次结构中只有一种类型,你知道先验Object

public void Bar<T>(T item)
{
    if (typeof(T).IsClass)
        this.Foo((object) item);
} 

编辑:

此外,在您说的其中一条评论中,您添加了class约束来实例化T。您不需要,您需要的是new constraint

答案 2 :(得分:0)

if (typeof(T).IsClass)
{
    this.GetType()
        .GetMethod("Foo", System.Reflection.BindingFlags.Instance |
                          System.Reflection.BindingFlags.Public)
        .Invoke(this, new object[] { item });
}

答案 3 :(得分:-1)

我相信没有办法让它编译。您将不得不使用反射来进行呼叫。

实际上。如果你在一个类中包含它,你可以作弊:

    public class Container<T>
    {
        public Container(T value)
        {
            Value = value;
        }

        public T Value { get; private set; }
    }

    public void Bar<T>(T item)
    {
        this.Foo<Container<T>>(new Container<T>(item));
    } 

但是这会增加一个你需要调用的图层,并使类型不那么清晰。