RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 994783
Accepted
Andrey K.
Andrey K.
Asked:2020-06-20 20:46:18 +0000 UTC2020-06-20 20:46:18 +0000 UTC 2020-06-20 20:46:18 +0000 UTC

C# 中用于 try-catch 的漂亮包装器

  • 772

问题不在于如何漂亮地编程以使这个问题不会出现,而是关于一个漂亮的包装器try-catch。

try
{

}
catch 
{
    // здесь ничего нет
}
  • 这是一件好事,但它占用了大量空间,我希望它可以放在一个块中,但执行相同的功能

我正在制作一段代码,它是一个安全网,根本不值得太多关注(现在我只关注未来,因为我已经不止一次地考虑过这个问题,好吧,放松一下)。优雅地重构是不值得的。你需要简单快速地说出来try,但我希望它看起来很漂亮。如果某些东西在那里不起作用,那没关系,但我也希望它不要在重要的地方出现异常,所以问题是关于try-catch.

有一个选项可以创建一个方法:

private void Try(Action codeBlock)
{
    try
    {
        codeBlock?.Invoke();
    } 
    catch 
    {
    } 
}

那么呼叫将在一行中,但此选项不是 100%,例如:

  • 这似乎不是一个美丽的挑战Try( ()=>DoWork() );,我想要更简单的东西,没有花里胡哨

  • 您可以将方法调用直接传递到参数Try(MethodCall)中,它看起来已经更好了,但是在我的特殊情况下,我将不得不将这个安全网和次要的方法分成许多部分,例如,如果情况是这样的:

    private static void EnsureSomethingWhichFailsAnyway(Someting input)
    {
        try
        {
            foreach (var x in input.GetAllX())
            {
                DoSmallThing(x);
                try
                {
                    x.SetPropertyValue = PossibleValues.BigValue;
                }
                catch { }
            }
        } catch { }
        try
        {
            foreach (var y in input.GetllY())
            {
                try
                {
                    y.Validate(StaticVars.A, StaticVars.B, StaticVars.C);
                }
                catch { }
            }
        }
        catch { }
    }
    
  • 也就是说,如果你把这样的方法分解成子方法来调用类型,Try(MethodCall)那么游戏就得不偿失了。

  • 有可能以某种方式放入using吗?

  • 也许没有理想的解决方案,那么只是听到建设性的想法很有趣。

谢谢!

c#
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Best Answer
    Andrey K.
    2020-06-21T00:46:53Z2020-06-21T00:46:53Z

    我想到了一个可以让你适应一个街区的想法。

    你可以像这样使用它:

        Try.AutoRunAction = () =>
        {
            //code block
        };
    

    这是原始实现:

        public class Try
        {
            // runs on set
            public static Action AutoRunAction
            {
                set
                {
                    try { value?.Invoke(); }
                    catch { }
                }
            }
        }
    
    • 与 from 方法相同,但括号更少
    • 曾经是一个吸气剂,建议删除
    • 也可以称为AutoTryAction
    • 接受批评

    例子:

        private static void SetAttributesNormal(DirectoryInfo dir)
        {
            AutoTryAction = () =>
            {
                foreach (var subDir in dir.GetDirectories())
                {
                    SetAttributesNormal(subDir);
                    AutoTryAction = () => subDir.Attributes = FileAttributes.Normal;
                }
            };
    
            AutoTryAction = () =>
            {
                foreach (var file in dir.GetFiles())
                {
                    AutoTryAction = () => file.Attributes = FileAttributes.Normal;
                }
            };
        }
    
        private static Action AutoTryAction
        {
            set
            {
                try { value?.Invoke(); }
                catch { }
            }
        }
    
    • 3
  2. nick_n_a
    2020-06-20T21:07:27Z2020-06-20T21:07:27Z

    相反,我建议将 try-catch 结合在一起,因为 我认为构建一个用于捕获错误的框架是一项代价高昂的操作。你可以用一个循环来做到这一点。让你有10个案例。相反,我try{}catch{}将不得不写case x:; break;我害怕获得可疑的收益。除非...自动代码编辑器不会把它变成 5 行。

    int nmax = 10;
    int step = 0;
    while (step < nmax) 
        try { // общий try
        for (int istep = step; istep < nmax; istep++)
           switch (istep) {
             case 0:;
                 break;
             case 1:;
                 break;
             // .....
              }
        } catch { step++;}
    

    封面好像很小。我认为如果没有例外,它将提高性能......但只是轻微的。更紧凑的版本

     for (int step=0;step<10;step++) try { switch (step) { 
         case 0:; break;
          //.... 
     } } catch {};
    

    据我了解,这并没有任何意义。

    • Try(MethodCall) 变体稍微耗时一些。
    • using 选项不能被明确地实现......好吧,除非你以与前一个选项相同的方式实现它using (var x=new Try(MethodCall))- 这将被扭曲。不管是什么变态……理论上,有可能发现错误的立场……但实际上,它不太可能奏效。

    选项2。基于选项1,并且知道代码行号,您可以萨满。但同样,“有条件地”。如果我们假设每一行都执行一次,那么我们可以这样做:

    bool ready = false;
    int step= 0;
    while (!ready) try {
         if (trysafe(ref step)) {  method1; /*шаг 1*/ };
         if (trysafe(ref step)) {  method2; /*шаг 2*/};
         ready = true;
         } catch {
         };
       }
    
    //  отсекатель
    bool trysafe(int ref kkey, [CallerLineNumber] int line = -1){
       if (kkey < line ) return false;
       kkey = line;
       return true;
       }
    

    出现异常时会发生循环,无论是否有异常都会跳过 if 中传入的方法。刀具可以通过字典制作(它会更“聪明”)。但是代码应该假设分解成步骤,就像前面的情况一样,但是步骤可以更“自由”地安排。步骤之间不应有间隙。对 trysafe 的调用必须始终出现在程序的不同行中。kkey 参数也可以根据情况缩短并移至全局范围。

    PS 静默异常使用起来很危险,因为最终很难找到错误。

    • 2
  3. Yaroslav
    2020-06-21T01:19:33Z2020-06-21T01:19:33Z

    您可以尝试功能方法:

    public readonly struct Try<T>
    {
        private readonly Lazy<(T, Exception)> factory;
    
        public Try(Func<(T, Exception)> factory) =>
            this.factory = new Lazy<(T, Exception)>(() =>
            {
                try
                {
                    return factory();
                }
                catch (Exception exception)
                {
                    return (default, exception);
                }
            });
    }
    
    public static class TryExtensions
    {
        public static Try<TResult> SelectMany<TSource, TSelector, TResult>(
            this Try<TSource> source,
            Func<TSource, Try<TSelector>> selector,
            Func<TSource, TSelector, TResult> resultSelector) =>
                new Try<TResult>(() =>
                {
                    if (source.HasException)
                    {
                        return (default, source.Exception);
                    }
                    Try<TSelector> result = selector(source.Value);
                    if (result.HasException)
                    {
                        return (default, result.Exception);
                    }
                    return (resultSelector(source.Value, result.Value), (Exception)null);
                });
    
        public static Try<TSource> Try<TSource>(this TSource value) => value;
    
        public static Try<TResult> Select<TSource, TResult>(
            this Try<TSource> source, Func<TSource, TResult> selector) =>
                source.SelectMany(value => selector(value).Try(), (value, result) => result);
    
        public static Try<T> Throw<T>(
            this Exception exception) => 
                new Try<T>(() => (default, exception));
    
        public static Try<T> Try<T>(Func<T> function) =>
            new Try<T>(() => (function(), (Exception)null));
    
        public static Try<T> Catch<T, TException>(
            this Try<T> source, Func<TException, Try<T>> handler, Func<TException, bool> when = null)
            where TException : Exception =>
                new Try<T>(() =>
                {
                    if (source.HasException && 
                        source.Exception is TException exception && 
                        exception != null && (
                        when == null || 
                        when(exception)))
                    {
                        source = handler(exception);
                    }
                    return source.HasException ? (default, source.Exception) : (source.Value, (Exception)null);
                });
    
        public static Try<T> Catch<T>(
            this Try<T> source, 
            Func<Exception, Try<T>> handler, 
            Func<Exception, bool> when = null) =>
                Catch<T, Exception>(source, handler, when);
    
        public static TResult Finally<T, TResult>(
            this Try<T> source, 
            Func<Try<T>, TResult> action) => action(source);
    
        public static void Finally<T>(
            this Try<T> source, 
            Action<Try<T>> action) => action(source);
    }
    

    例子:

    internal static Try<int> Example(int? value)
    {
        if (value == null)
        {
            return Throw<int>(new ArgumentNullException(nameof(value)));
        }
    }
    

    关于它的来源:C# Fundamentals 的类别理论

    视频:uDev Tech Meetup #10:函数式 C#

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5