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));