如何传递一个泛型参数?

7

我正在尝试编写以下内容:

public void Foo<T>(T parameter) {
  otherObject.Bar<T>(parameter);
}

Bar()方法的签名为:
public void Bar<T>(T parameter) where T: class 

因为Foo中的T约束不同,所以我会得到编译错误。不幸的是,我不能这样写:

public void Foo<T>(T parameter) where T: class {
  otherObject.Bar<T>(parameter);
}

因为Foo正在实现一个外部接口定义的方法。问题是:

我是否可以在调用Bar之前在方法Foo中转换T?(注意,我可以确定T始终是一个类 - 我只需要通过编译器即可)。

我找到的唯一方法是使用反射,但我想知道是否有我错过的更简单的技巧。


7
不行,没有其他办法。 - SLaks
Foo<T>方法的类签名是什么? - Felipe Oriani
4个回答

9
你可以像这样使用 dynamic 关键字
public void Foo<T>(T parameter)
{
    dynamic p = parameter

    otherObject.Bar(p);
}

发生的情况是由于其中一个参数具有动态类型,因此对otherObject.Bar的调用分辨率是在运行时进行的。假设T是引用类型,则分辨率将成功。
当然,这最终使用了反射(如您所示),但语法可能比您使用的更好。
当然,如果T不是类,则会在运行时出现错误。

谢谢 - 是的,你的代码比我的反射解决方案更小/更整洁,我的反射解决方案是:otherObject.GetType().GetMethod("Bar").MakeGenericMethod(typeof (T)).Invoke(otherObject, new object[] {parameter}); - Richard Pawson

4
public void Foo<T>(T parameter)
{
    otherObject.Bar<object>(parameter);
}

+1 我本来就想说这个。虽然我不太明白为什么它能工作,因为值类型也可以被转换为“object”。 - mellamokb
3
值类型不会被转换为 object,它们会被装箱。 - casperOne
如果是这样的话,那么在泛型方面,结构体/类区分的整个意义是什么? - mellamokb
@mellamokb 这里的目的是让你可以对类型参数 T 执行操作,例如与 null 进行比较等。如果你将值类型装箱,那么这个装箱后的值就是一个 object,你可以在这个 object 上执行任何引用类型的操作。 - casperOne

3
这里提供一种略有不同的方法,采用隐式接口实现方式,与casperOne的回答不同。
public void Foo<T>(T parameter) where T: class {
    otherObject.Bar<T>(parameter);
}

void IFoo.Foo<T>(T parameter){
    Foo((dynamic)parameter);
}

这样做可以让你在编译时将约束包含在任何知道自己调用的具体对象类型的.Foo上,同时仍允许你实现IFoo接口。


0

如果您是otherObject.Bar的所有者,您是否可以移除该方法的类约束?或创建一个新的类似方法而无需使用约束条件?

casperOne。我不确定您的答案是否正确,因为您在Foo方法上有类约束。问题说明这是不可能的,因为Foo是外部接口的实现。例如,下面的代码无法正常工作。

public void Foo<T>(T param)
    {
        dynamic xx = param;

        this.Bar(param);
    }

    private void Bar<T>(T param) where T: class {

    }

并显示为错误。


它会显示为错误,因为您没有将 xx 传递给 Bar,而是仍然从 Foo 传递了 param - casperOne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接