我正在尝试创建一个接受另一个方法的方法,并返回内部方法返回的值(如果该内部方法不无效)。我想做到这一点而又不区分Func<>
和Action<>
。
从本质上讲,我希望包装方法的行为与未包装方法完全相同,并希望包装程序提供一些功能。这个目标很简单,但是很难将我的想法笼罩在实现中。
public int ReturnsInteger() {
Console.WriteLine("I return 42");
return 42;
}
public static T WrapperMethod(Func<T> someMethod) {
Console.WriteLine("Wrap start");
var result = someMethod();
Console.WriteLine("Wrap end");
return result;
}
private static void Main() {
var X = WrapperMethod(()=>ReturnsInt());
Console.WriteLine("X = " + X);
// Wrap start
// I return 42
// Wrap end
// X = 42
}
public void ReturnsNothing() {
Console.WriteLine("I return nothing");
return;
}
public static T WrapperMethod(Action someMethod) {
Console.WriteLine("Wrap start");
someMethod();
Console.WriteLine("Wrap end");
}
private static void Main() {
WrapperMethod(()=>ReturnsNothing());
// Wrap start
// I return nothing
// Wrap end
}
答案 0 :(得分:0)
如上所述,我并不完全理解您的问题的措辞。但是,基本情况似乎很简单:您希望以一般方式修饰未知方法的行为,同时处理返回值的方法和不返回值的方法。
每当遇到这种情况时,我都会编写一个返回类型为void
的包装器方法,然后通过lambda适应第二个包装器方法来解决该问题。例如:
T Wrapper<T>(Func<T> func)
{
T result = default(T);
Wrapper(() => { result = func(); });
return result;
}
void Wrapper(Action action)
{
Console.WriteLine("Wrap start");
action();
Console.WriteLine("Wrap end");
}
这样,我只需要编写一次包装逻辑。 Func<T>
版本必须创建一个新的委托实例并捕获一个局部变量,这会产生一些开销,但是至少当我必须要做这种事情时,包装逻辑和包装逻辑非常复杂,以至于Lambda的开销无关紧要。
答案 1 :(得分:0)
我会尝试通过实际给该方法一些返回的东西来消除void
返回方法的基本语言差异。
通过实现Unit
类型(即单个值struct
),您可以将Action
转换为Func<Unit>
。实际上,这只是使用适配器模式。
现在,您正在处理Func<T>
形式的一种委托。然后,您可以将所有艰苦的工作投入到单个Wrapper
方法中。
尝试一下:
void Main()
{
var result = Wrapper(DoSomething);
}
private void DoSomething()
{
Console.WriteLine("Test.");
}
T Wrapper<T>(Func<T> func)
{
Console.WriteLine("Wrap start");
var result = func();
Console.WriteLine("Wrap end");
return result;
}
Unit Wrapper(Action action)
{
return Wrapper(() => { action(); return Unit.Default; });
}
/// <summary>
/// Represents a type with a single value. This type is often used to denote the successful completion of a void-returning method (C#) or a Sub procedure (Visual Basic).
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct Unit : IEquatable<Unit>
{
public static Unit Default => default(Unit);
public bool Equals(Unit other) => true;
public override bool Equals(object obj) => obj is Unit;
public override int GetHashCode() => 0;
public override string ToString() => "()";
public static bool operator ==(Unit first, Unit second) => true;
public static bool operator !=(Unit first, Unit second) => false;
}