C# 编写一个函数,该函数接受具有常见返回类型的任意对象和方法

C# 编写一个函数,该函数接受具有常见返回类型的任意对象和方法,c#,C#,我有几个不同类型的对象,它们的方法采用不同的参数,所有这些参数都返回相同的类型。这些方法可能会失败。是否有一种方法可以编写一个函数,该函数将接受对象及其方法,指示该方法是否失败,以及指示发生故障的对象?我无法修改结果对象,它不包含有关调用它的对象的信息 我觉得这有点冗长: Result resultA = A.something(); if(resultA.Failed) return new Status{Failed=A.GetType().ToString()}; Result resu

我有几个不同类型的对象,它们的方法采用不同的参数,所有这些参数都返回相同的类型。这些方法可能会失败。是否有一种方法可以编写一个函数,该函数将接受对象及其方法,指示该方法是否失败,以及指示发生故障的对象?我无法修改结果对象,它不包含有关调用它的对象的信息

我觉得这有点冗长:

Result resultA = A.something();
if(resultA.Failed) return new Status{Failed=A.GetType().ToString()};

Result resultB = B.somethingElse(3);
if(resultB.Failed) return new Status{Failed=B.GetType().ToString()};

Result result3 = C.someOtherThing("apple");
if(resultC.Failed) return new Status{Failed=C.GetType().ToString()};

// Do some processing of the results (will succeed if A,B,C succeeded)

return new Status {Failed=null, Success=true};
有没有办法将所有这些封装到一个函数中?这似乎很重复。A、 B、B和C不是从有用的基类继承的,它们的方法都采用不同的参数并具有不同的名称


也就是说,我确实可以访问Status类,甚至可以访问这个函数的返回值。函数不需要返回,它可以抛出异常。如果出现故障,函数可以立即中断。

最简单的方法是创建一个新的
Status
子类,为您填充
Failed
属性,您可以让构造函数将
对象作为类型,并在其中调用
GetType()

public class FailedStatus : Status
{
    public FailedStatus(object source)
    {
        this.Failed = source.GetType().ToString();
    }
}

Result resultA = A.something();
if(resultA.Failed) return new FailedStatus(A);

Result resultB = B.somethingElse(3);
if(resultB.Failed) return new FailedStatus(B);

Result result3 = C.someOtherThing("apple");
if(resultC.Failed) return new FailedStatus(C);


如果
结果
派生自
状态
,最简单的方法是修改
某物()
某物(int)
,以及
某物(字符串)
,以设置字符串本身(但我怀疑这是不是真的,它似乎是
结果。Failed
是一个
bool
状态。Failed
是一个
字符串
)。

一种简单的方法可以做到这一点:

//Note: the method signature could just be IEnumerable<Result> AggregateResults(params Func<Result>[]) 
//if you want to be able to aggregate the results of 0 calls
IEnumerable<Result> AggregateResults(Func<Result> func, params Func<Result>[] otherFuncs)
{
    yield return func();
    foreach(var otherFunc in otherFuncs)
        yield return otherFunc();
}

//Usage:
var results = AggregateResults(
    () => A.Something(),
    () => B.SomethingElse(3),
    () => C.SomethingOtherThing("apple"));
//注意:方法签名只能是IEnumerable AggregateResults(params Func[])
//如果希望能够聚合0次调用的结果
IEnumerable聚合结果(Func Func,params Func[]otherFuncs)
{
收益率返回函数();
foreach(otherFunc中的var otherFunc)
返回otherFunc();
}
//用法:
var结果=聚合结果(
例如:某物,
()=>B.SomethingElse(3),
()=>C.SomethingOtherThing(“苹果”);
不幸的是,在第一次失败调用时停止并获取调用对象的要求使其变得稍微困难:

class AggregateResult
{
    public object CallingObject;
    public Result Result;

    public static AggregateResult Create<T>(T t, Func<T,Result> func) 
    { 
        return new AggregateResult() { CallingObject = t, Result = func(t) }; 
    }
}
IEnumerable<AggregateResult> AggregateResults(Func<AggregateResult> func, params Func<AggregateResult>[] otherFuncs)
{
    yield return func();
    foreach (var otherFunc in otherFuncs)
        yield return otherFunc();
}
//Usage:
var results = AggregateResults(
            () => AggregateResult.Create(A, x=>x.Something()),
            () => AggregateResult.Create(B, x=>x.SomethingElse(3)),
            () => AggregateResult.Create(C, x=>x.SomethingOtherThing("apple")));
var failedResult = results.FirstOrDefault(x => x.Result.Failed);
if (failedResult != null) return new Status() { Failed = failedResult.CallingObject.GetType().ToString() };
类聚合结果
{
公共对象调用对象;
公共结果;
公共静态聚合结果创建(T,Func-Func)
{ 
返回新的AggregateResult(){CallingObject=t,Result=func(t)};
}
}
IEnumerable聚合结果(Func Func,params Func[]otherFuncs)
{
收益率返回函数();
foreach(otherFunc中的var otherFunc)
返回otherFunc();
}
//用法:
var结果=聚合结果(
()=>AggregateResult.Create(A,x=>x.Something()),
()=>AggregateResult.Create(B,x=>x.SomethingElse(3)),
()=>AggregateResult.Create(C,x=>x.something其他东西(“苹果”));
var failedResult=results.FirstOrDefault(x=>x.Result.Failed);
if(failedResult!=null)返回新状态(){Failed=failedResult.CallingObject.GetType().ToString()};

也就是说,我同意这听起来像是XY问题的评论。

您可以为结果创建一个扩展方法,如果成功,该方法将返回null,如下所示:

static class ResultExtension 
{
    public static Status GetStatus<T>(this Result res, T a) {
        return res.Failed? new Status{Failed=a.GetType().ToString()} : null;
    }
}

请注意,如果之前的结果都不为空(即失败),那么您只需对somethingElse(3)或somethingthing(“苹果”)进行评估,最终,如果且仅当所有呼叫都成功时,您才会返回成功状态。

我建议对@Shawn Holzworth的答案进行一个简单的小改动

首先,由于您的方法的唯一共同点是它们的返回类型,因此这是我们在这里可以概括的唯一内容。我们可以构造一个方法,按照您的请求处理执行,如下所示:

 public static Status ExecuteRequests(params Func<Result>[] actions){
  foreach (Func<Result> action in actions) {
    Result r = action();
    if (!r.Success) {
      Status s = new Status() { Failed = action.Target.GetType().ToString() };
      return s;
    }
  }

  return new Status() { Success = true };
}
如果要对结果执行额外的计算,可以扩展ExecuteRequests方法以操作的形式输入处理程序

这个抽象实际上促进了另一件你没有问过的事情,但我认为值得一提的是:并行执行。当你像这样封装这些操作时,很容易利用TPL,并行发送请求并在到达时聚合它们,但这有点复杂


上面提到过,我想知道这是否值得努力。实际上,它抽象了执行序列,但我不确定这是否会显著提高可读性(除非您的执行序列长于3,并且预计将来会增长).

这听起来像是一个,你能更全面地描述一下发生了什么吗?在黑暗中拍摄,你正在使用WCF,这是为了在不影响连接的情况下反馈错误?我正在调用MVC web服务。我从不同的客户端调用了几个,所有这些调用都返回一个带有http状态码的结果。你的示例需要一点le澄清:如果,比如说,所有方法都成功了,那么输出应该是什么?另一方面,如果其中一个方法失败了,你想继续执行其他方法还是立即中断?这很完美。谢谢!我喜欢这种方法,但要注意:
action.Target.GetType()
A.GetType()不同
action.Target
将是调用
ExecuteRequest(()=>A.doSomething())
的对象,或者如果您首先定义
Func
函数,比如
Func f=()=>A.Something();
@ShawnHolzworth,您当然是对的。Eric可以合并您的方法的一部分(创建方法)但我担心,这样的收获不值得付出努力和间接努力。
 public static Status ExecuteRequests(params Func<Result>[] actions){
  foreach (Func<Result> action in actions) {
    Result r = action();
    if (!r.Success) {
      Status s = new Status() { Failed = action.Target.GetType().ToString() };
      return s;
    }
  }

  return new Status() { Success = true };
}
  ExecuteRequests(
    () => A.doSomething(), 
    () => B.doSomethingElse(42));