我想为泛型类型编写扩展方法,并使用其他泛型类型参数。我已经有了工作代码,但不喜欢结果,因为用户需要重新输入现有类型的泛型类型参数。
我有一个具体的例子,但请记住,这是一个普遍的问题。我很欣赏有关手头特定问题的反馈,但我正在寻找一般解决方案。
对于类型Action<T>
的类,添加一个带有与此类似的签名的扩展方法:
Func<T, TResult> ToFunc<TResult>();
这是我的工作代码:
public static class DelegateExtensions
{
public static Func<T, TResult> ToFunc<T, TResult>(this Action<T> action)
{
return arg => { action(arg); return default(TResult); };
}
}
但是用法很糟糕:
public void TakesAFunc(Func<int, float> someFunc) { /* ... */ }
// ...
Action<int> someIntAction = /* ... */;
TakesAFunc(someIntAction.ToFunc<int, float>());
在此示例中,int
泛型参数是唯一可接受的值,因此会导致不必要的代码重复。
类型推断在这里不起作用。我认为这是因为您无法通过返回类型推断出通用参数。
此代码可以解决问题,但遗憾的是似乎不起作用:
public static class DelegateExtensions<T>
{
public static Func<T, TResult> ToFunc<TResult>(this Action<T> action)
{
return arg => { action(arg); return default(TResult); };
}
}
用法与您期望的完全一样:
public void TakesAFunc(Func<int, float> someFunc) { /* ... */ }
// ...
Action<int> someIntAction = /* ... */;
TakesAFunc(someIntAction.ToFunc<float>());
我注意到System.Linq.Queryable
的工作方式与我的第一个代码块相同,但它通常不需要额外的类型参数,因此类型推断可以工作。
是否有任何已知的技巧可以解决这些重复的泛型类型参数?想到的一个想法是代码生成器或某种类型的宏,但我想不出我是如何干净地完成的。
答案 0 :(得分:3)
这类事情的一个常见技巧是为类型推断传递所需类型的虚拟值,这在某些涉及匿名类型的场景中是必需的。
public static class DelegateExtensions
{
public static Func<T, TResult>
ToFunc<T, TResult>(this Action<T> action, TResult ignored)
{
return arg => { action(arg); return default(TResult); };
}
}
这是多么好的伎俩取决于个人意见,但每当我打电话给我时,每次我回到我称之为的地方时,这都会让我感到困惑。您还可以更改方法的语义,使第二个参数成为返回值,允许调用者决定是否需要默认值。
至于你的第二个例子,我很确定泛型类型不允许使用扩展方法,但是我没有方便的链接
答案 1 :(得分:2)
我迟到了 - 抱歉。
如前所述 - 目前无法将 Func 切换为out参数。
我会抛弃另一种方法来做这种事情 - 它看起来有点流畅的语法,但它的工作原理。
public class ActionWrap<T>
{
private readonly Action<T> _action;
internal ActionWrap(Action<T> action)
{
_action = action;
}
public Func<T, TResult> OfType<TResult>()
{
return arg => { _action(arg); return default(TResult); };
}
}
public static class DelegateExtensions
{
public static ActionWrap<T> ToFunc<T>(this Action<T> action)
{
return new ActionWrap<T>(action);
}
}
然后调用它:
Action<int> x = z=> Console.WriteLine(z);
Func<int, float> asFunc = x.ToFunc().OfType<float>();
这不是你想要的,但它实现了不再说明int泛型的目标,并且可以扩展到你想要做类似事情的其他情况。