Func<>使用基类作为参数
本文关键字:参数 基类 Func | 更新日期: 2023-09-27 17:56:02
>我有一堆方法,我想检查一些元数据,它们都有不同的参数,但参数都派生自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有一个派生类作为参数,而不是一个基类。我尝试使用泛型:
public void CheckMethod<T>(Func<T, Object> func)
...
CheckMethod<DerivedClass>(MethodToCheck);
我希望对 CheckMethod 的调用尽可能少地键入,并且宁愿只用 CheckMethod(MethodToCheck)
调用它。这可能吗?
查看有关协方差和逆变的 MSDN 页面。本文似乎表明您无法在以前的版本中实现此目的。
如果您坚持使用旧版本,我建议您探索访问者模式。
像这样的东西怎么样
public void CheckMethod<T>(Func<T, Object> func) where T : BaseClass
这似乎是 C# 语言设计者没有想到的。您(和我)正在寻找的是 Funcs/Delegates 的编译时"接口",因此它们基本上可以在集合中使用。
问你的问题的另一种方法是我如何约束传递这样的数组的人:
new[] {
new Func<MaxLengthAttribute, string>(a => "maxlength=" + a.Length),
new Func<RequiredAttribute, string>(a => "required")
}
只传递格式的函数Func<out Attribute, string>
?应该很简单...不?
不。作为链接到的另一个答案,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)
{
}
呃。同样,我的数组示例变为: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);
现在将得到一个编译错误,因为编译器准确地断言它不知道这个委托是否接受任何参数。可爱。您可以使用以下命令跳过它以运行时:
var b = (B)fn.DynamicInvoke(a);
相关