C# 如何生成返回包装方法的通用包装方法';如果有,结果是什么?

C# 如何生成返回包装方法的通用包装方法';如果有,结果是什么?,c#,generics,methods,delegates,C#,Generics,Methods,Delegates,我试图创建一个接受另一个方法的方法,如果该内部方法不是void,则返回该内部方法返回的值。我希望在不区分Func和Action的情况下执行此操作 本质上,我希望wrapped方法的行为方式与unwrapped方法完全相同,再加上wrapper提供的一些功能。目标很简单,但很难理解实现 public int ReturnsInteger(){ Console.WriteLine(“我返回42”); 返回42; } 公共静态T包装器方法(Func someMethod){ 控制台。WriteLine

我试图创建一个接受另一个方法的方法,如果该内部方法不是void,则返回该内部方法返回的值。我希望在不区分
Func
Action
的情况下执行此操作

本质上,我希望wrapped方法的行为方式与unwrapped方法完全相同,再加上wrapper提供的一些功能。目标很简单,但很难理解实现

public int ReturnsInteger(){
Console.WriteLine(“我返回42”);
返回42;
}
公共静态T包装器方法(Func someMethod){
控制台。WriteLine(“包装启动”);
var result=someMethod();
控制台。写入线(“包装端”);
返回结果;
}
私有静态void Main(){
var X=WrapperMethod(()=>ReturnsInt());
Console.WriteLine(“X=”+X);
//换行开始
//我返回42
//包端
//X=42
}
public void ReturnsNothing(){
Console.WriteLine(“我不返回任何内容”);
返回;
}
公共静态T包装器方法(Action someMethod){
控制台。WriteLine(“包装启动”);
somethod();
控制台。写入线(“包装端”);
}
私有静态void Main(){
WrapperMethod(()=>ReturnsNothing());
//换行开始
//我什么也不退
//包端
}

如上所述,我不完全理解你问题的措辞。然而,基本的场景似乎很简单:您希望一般地修饰未知方法的行为,处理返回值的方法和不返回值的方法

每当遇到这种情况时,我都会编写一个返回类型为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");
}
T包装器(Func-Func)
{
T结果=默认值(T);
包装器(()=>{result=func();});
返回结果;
}
无效包装器(操作)
{
控制台。WriteLine(“包装启动”);
动作();
控制台。写入线(“包装端”);
}

这样,我只需编写一次包装器逻辑。
Func
版本必须创建一个新的委托实例并捕获一个局部变量,这会带来一些开销,但至少当我不得不做这种事情时,包装逻辑和包装逻辑非常复杂,因此lambda的开销是无关紧要的。

我会尝试通过实际给方法返回的内容来消除
void
返回方法的基本语言差异

通过实现一个
单元
类型,即一个单一的值
结构
,您可以将
操作
转换为
函数
。这实际上只是使用适配器模式

现在您只需要处理一种形式为
Func
的委托。然后,您可以将所有的艰苦工作放在单个
包装器
方法中

试试这个:

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;
}
void Main()
{
var结果=包装(剂量计);
}
私人无效剂量()
{
控制台。写线(“测试”);
}
T包装器(Func Func)
{
控制台。WriteLine(“包装启动”);
var result=func();
控制台。写入线(“包装端”);
返回结果;
}
单元包装器(动作)
{
返回包装(()=>{action();return Unit.Default;});
}
/// 
///表示具有单个值的类型。此类型通常用于表示成功完成了一个空返回方法(C#)或一个子过程(Visual Basic)。
/// 
[可序列化]
[StructLayout(LayoutKind.Sequential,Size=1)]
公共结构单元:IEquatable
{
公共静态单位默认值=>默认值(单位);
公共布尔等于(其他单位)=>真;
公共覆盖布尔等于(对象obj)=>obj为单位;
公共覆盖int GetHashCode()=>0;
公共重写字符串ToString()=>“()”;
公共静态布尔运算符==(单位第一,单位第二)=>true;
公共静态布尔运算符!=(单元第一,单元第二)=>错误;
}

您将需要对
操作
函数
进行重载,但是您可以实现一个
单元
类型,由
操作
的包装器返回。您提出的任何解决方案都将比这里的解决方案更加复杂,性能也会非常差。试图概括这一点并不能简化这一点。只需支持两个不同的委托,“我试图创建一个接受另一个方法的方法,并返回内部方法返回的值,如果该内部方法不是void”——我甚至不知道这意味着什么。也就是说,如果内部方法的返回类型为
void
,那么您不希望您的方法返回值吗?C#不是那样的。方法总是要么返回值,要么不返回值。你不能让它们根据参数有条件地返回值。这里你只有一半的需求。为了使它们完整,您必须指定如果内部方法确实返回
void
,您希望包装器方法做什么。我花了将近一个小时试图找出如何提出正确的问题,但是@PeterDuniho的回答抓住了问题的要点。谢谢你的回答。我觉得奇怪的是,C#必须独立于其他方法处理无效方法,但这似乎足够优雅。不管是好是坏,C#遵循C和类似语言设置的约定,所有这些语言都处理返回类型不同于无返回类型的方法。我想C#设计器可能偏离了这一标准,我怀疑这是基于底层架构的(对于基于x86的处理器,返回值与否是有区别的),但这可能会让试图从其他语言迁移的程序员更加惊恐。的确,我不知道有哪种主流的静态类型语言没有这种区别