很抱歉,标题不清楚。基本上,我想通过将许多重复的错误处理移到一个位置来干燥我的代码。
我正在调用几种方法,所有方法都会引发类似的错误。每个参数采用不同的参数,并返回不同的类型。我希望能够执行以下操作:
public class MyClass {
public static ErrorWrapper<Void> Method1(string s1, string s2) {
return Wrapper<Void>(System.Method1, s1, s2);
}
public static ErrorWrapper<string> Method2(string s) {
return Wrapper<string>(System.Method2, s);
}
public static ErrorWrapper<MyOtherClass> Method3(string s, int i) {
return Wrapper<MyOtherClass>(System.Method3, s, i)
}
private static ErrorWrapper<T> Wrapper<T>(Func f, /*parameters?*/) {
try {
return f(parameters);
} catch {
// Handle exceptions
}
}
之所以需要这样做,是因为我编写的语言绑定没有异常处理,因此使用错误包装类是安全地调用标准库方法的唯一方法。
答案 0 :(得分:2)
除非我在这里缺少任何内容-
private static ErrorWrapper<T> Wrapper<T>(Func<T> f)
{
// implementation
}
用法:
return Wrapper<string>(() => System.Method2(s));
return Wrapper<MyOtherClass>(() => System.Method3(s, I));
答案 1 :(得分:0)
这是我对您正在尝试的理解的建议。不幸的是,您必须使用慢的DynamicInvoke
才能在调用常规Delegate
时在运行时检查类型。您不能使用void
作为泛型的类型参数,因此我创建了一个我专门处理的MyVoid
类。
我更新了答案,以反映System.Method
是实际方法,而不是静态字段,因此在传递给Wrapper<>
时必须将其强制转换-C#无法将方法转换为一般Delegate
。
我还添加了类型安全的版本,但是需要创建许多样板方法来处理参数数量,但是它确实消除了很多强制转换并且可以静态调用委托,这应该更高效。
我不小心使Method3
最初使用了两个字符串参数,并且非类型安全版本直到运行时调用才出现错误。类型安全版本在编译时遇到了错误。
public class MyVoid { }
public class ErrorWrapper<T> {
public T Result;
public bool ValidResult;
public Exception Exception;
public ErrorWrapper(T res) {
ValidResult = true;
Result = res;
}
public ErrorWrapper(Exception e) {
Exception = e;
ValidResult = false;
}
public ErrorWrapper() { // void
ValidResult = true;
}
}
public class MyClass {
public static ErrorWrapper<MyVoid> Method1(string s1, string s2) => Wrapper<MyVoid>((Action<string, string>)System.Method1, s1, s2);
public static ErrorWrapper<string> Method2(string s) => Wrapper<string>((Func<string, string>)System.Method2, s);
public static ErrorWrapper<MyOtherClass> Method3(string s, int i) => Wrapper<MyOtherClass>((Func<string, int, MyOtherClass>)System.Method3, s, i);
private static ErrorWrapper<T> Wrapper<T>(Delegate f, params object[] p) {
try {
switch (default(T)) {
case MyVoid _:
f.DynamicInvoke(p);
return new ErrorWrapper<T>();
default:
return new ErrorWrapper<T>((T)f.DynamicInvoke(p));
}
}
catch (Exception e) {
// Handle exceptions
return new ErrorWrapper<T>(e);
}
}
}
public static class ErrorWrapper {
public static ErrorWrapper<T> New<T>(T res) => new ErrorWrapper<T>(res);
}
public class MyTypeSafeClass {
public static ErrorWrapper<MyVoid> Method1(string s1, string s2) => WrapperAction(System.Method1, s1, s2);
public static ErrorWrapper<string> Method2(string s) => WrapperFunc(System.Method2, s);
public static ErrorWrapper<MyOtherClass> Method3(string s, int i) => WrapperFunc(System.Method3, s, i);
private static ErrorWrapper<MyVoid> WrapperAction<T1, T2>(Action<T1, T2> f, T1 p1, T2 p2) {
try {
f(p1, p2);
return ErrorWrapper.New(default(MyVoid));
}
catch (Exception e) {
// Handle exceptions
return new ErrorWrapper<MyVoid>(e);
}
}
private static ErrorWrapper<TRes> WrapperFunc<T1, TRes>(Func<T1, TRes> f, T1 p1) {
try {
return ErrorWrapper.New(f(p1));
}
catch (Exception e) {
// Handle exceptions
return new ErrorWrapper<TRes>(e);
}
}
private static ErrorWrapper<TRes> WrapperFunc<T1, T2, TRes>(Func<T1, T2, TRes> f, T1 p1, T2 p2) {
try {
return ErrorWrapper.New(f(p1, p2));
}
catch (Exception e) {
// Handle exceptions
return new ErrorWrapper<TRes>(e);
}
}
}