【问题标题】:C# Method which takes another method as an argument regardless of input/return type无论输入/返回类型如何,都将另一个方法作为参数的 C# 方法
【发布时间】:2019-12-28 05:26:16
【问题描述】:

如果标题不清楚,我很抱歉。基本上我想通过将大量重复的错误处理移到一个地方来干燥我的代码。

我正在调用几种方法,它们都会引发类似的错误。每个都接受不同的参数,并返回不同的类型。我希望能够做这样的事情:

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
        }
}

我需要这样做,因为我正在为一种没有异常处理的语言编写绑定,所以使用错误包装类是安全调用标准库方法的唯一方法。

【问题讨论】:

  • 你试过dynamic吗?
  • ErrorWrapper&lt;Void&gt; 是什么?你真的有一个叫Void的类型吗?
  • @ATC 是的,我是从母语导入的。

标签: c# functional-programming


【解决方案1】:

除非我在这里遗漏了什么 -

private static ErrorWrapper<T> Wrapper<T>(Func<T> f) 
{
    // implementation
}

用法:

return Wrapper<string>(() => System.Method2(s));

return Wrapper<MyOtherClass>(() => System.Method3(s, I));

【讨论】:

    【解决方案2】:

    根据我对您的尝试的理解,这是我的建议。不幸的是,您必须使用很慢的DynamicInvoke,以便在调用通用Delegate 时在运行时检查类型。你不能使用void 作为泛型的类型参数,所以我创建了一个我专门处理的MyVoid 类。

    我更新了我的答案以反映 System.Methods 是实际方法,而不是静态字段,因此在传递给 Wrapper&lt;&gt; 时必须强制转换它们 - 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);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 2021-11-21
      • 2020-10-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多