我有一堆方法要检查一些元数据,所有这些方法都有不同的参数,但参数都来自BaseClass
。
public void CheckMethod(Func<BaseClass, Object> func)
{
// Check method metadata here
}
public Object MethodToCheck(DerivedClass foo)
{
// Whatever...
}
public void Test()
{
CheckMethod(MethodToCheck);
}
代码在CheckMetadata(MethodToCheck)
上失败,因为MethodToCheck将DerivedClass作为参数而不是BaseClass。我尝试过使用泛型:
public void CheckMethod<T>(Func<T, Object> func)
...
CheckMethod<DerivedClass>(MethodToCheck);
我希望CheckMethod的调用尽可能少,并且只希望用CheckMethod(MethodToCheck)
调用它。这可能吗?
答案 0 :(得分:2)
像
这样的东西public void CheckMethod<T>(Func<T, Object> func) where T : BaseClass
答案 1 :(得分:1)
Check out the MSDN page on covariance and contravariance。这篇文章似乎暗示你在以前的版本中无法做到这一点。
如果您遇到旧版本,我建议您浏览访问者模式。
答案 2 :(得分:0)
这似乎是C#语言设计师没有想到的。你(和我)正在寻找的是一个编译时间&#34;接口&#34;对于Funcs / Delegates,它们基本上可以用在集合中。
另一种提出问题的方法是如何限制传递数组的人:
new[] {
new Func<MaxLengthAttribute, string>(a => "maxlength=" + a.Length),
new Func<RequiredAttribute, string>(a => "required")
}
仅传递格式为Func<out Attribute, string>
的Func?应该简单......不是吗?
没有。正如另一个答案所关联的那样,out关键字不允许输入参数,例如我们在此处使用的参数。
如果你必须在编译时拥有约束,你就会陷入类似Java的丑陋杂技:
public interface IHasMethod<T>
where T : BaseClass
{
void MethodToCheck<T>(T, object);
}
public class Class1 : IHasMethod<DerivedClass>
{
public object MethodToCheck(DerivedClass d)
{
}
}
表示您的测试如下:
public void CheckMethod(IHasMethod methodHaver)
{
}
Eugh。同样,我的数组示例变为:new IHasMethod[]
如果您更喜欢在运行时受到保护/检查的更漂亮,更脆弱的代码,您的替代方案是Delegate
。你的签名:
public void CheckMethod(Delegate func)
我的数组示例:
new Delegate[] ...
但是在这两种情况下你都处于危险之中,因为委托的格式在编译时是无限制的 - 现在你正在做你通常会遇到编译器的问题,在继续之前检查正确数量的参数及其类型。如果可以,请尝试仅对调试代码进行丑陋的检查,并且对方法的任何调用都会被提取并暴露给单元测试,因此即使您已经失去编译安全性,也可以使用自动测试安全性替换它。像:
#if DEBUG
foreach(var attrTempl in attributeTemplates)
{
var templParams = attrTempl.Method.GetParameters();
if (templParams.Length != 1)
throw new Exception("Can't have " + templParams.Length + " params in AttributeTemplate Delegate, must be Func<out Attribute, string>");
var type1 = templParams[0].ParameterType;
var type2 = attrTempl.Method.ReturnType;
if (!type1.IsSubclassOf(typeof(System.Attribute)))
throw new Exception("Input parameter type " + type1.Name + " must inherit from System.Attribute");
if (type2 != typeof(string))
throw new Exception("Output parameter type " + type2.Name + " must be string");
}
#endif
支持障碍的最后一个帮助:如果采用Delegate
方法,您将转换如下代码:
Func<A, B> fn
对此:
Delegate fn
你可能在某些时候称Func为:
var b = fn(a);
现在会出现编译错误,因为编译器准确断言它不知道此Delegate是否接受任何参数。可爱。您可以通过以下方式将其过去运行:
var b = (B)fn.DynamicInvoke(a);