【问题标题】:Elegant C# method to return an IEnumerable<T> from a function which is bool TryParse<T>(Input, out T) and an input[,]优雅的 C# 方法从 bool TryParse<T>(Input, out T) 和 input[,] 的函数返回 IEnumerable<T>
【发布时间】:2014-08-29 18:58:04
【问题描述】:

有没有一种优雅的方式来构建一个IEnumerable&lt;T&gt;

bool TryParse<T>(Input, out T) 

和一个类型的输入

Input[,]

基本上我有一个输入的二维数组,并且想在每个输入上调用 TryParse,如果 TryParse&lt;T&gt; 返回 true,我会将“out”中的返回值附加到 IEnumerable&lt;T&gt;

我可以在 for 循环中轻松做到这一点,但我想要更优雅的东西。这是我目前使用的:

        var marketInputColl = new Collection<MarketInput>();
        foreach (object o in marketInputs)
        {
            MarketInput mktInput;
            if (ExcelCache.TryGetCache<MarketInput>(o.ToString(), out mktInput))
                marketInputColl.Add(mktInput);
        }

【问题讨论】:

  • Input 是一种类型吗?你尝试了什么?
  • 有一些“优雅”的方法可以做你想做的事,但它们比简单的foreach 循环更复杂,更难理解。
  • 我意识到这不是 100% 的重复,但它是迭代二维数组的一个微不足道的扩展。
  • @Heinzi 是的,但是在泛型上使用加法运算符并不容易
  • Input 是一种类型,我可以使用 for 循环,我不知道如何在 LINQ 表达式中 TryParse 的返回值的函数中选择性地添加到 Enum。

标签: c#


【解决方案1】:

out/ref 参数在 LINQ 中并不能很好地发挥作用。你可以做到,但它很混乱。更可取的选择是使用解析工具,该工具将返回一个可为空的 int(如果无法解析该值,则返回 null),而不是使用 out

public static int? TryParse(string s)
{
    int output;
    if (int.TryParse(s, out output))
        return output;
    else
        return null;
}

您可以为尝试从缓存中获取值创建一个类似的函数,只要您不需要存储 实际 null 值。

这允许你写:

var query = data.Select(item => TryGetCache(item.ToString()))
    .Where(n => n != null);

【讨论】:

    【解决方案2】:

    你可以用通用的方式来做:

    static class Extensions
    {
        public delegate bool TryParseDelegate<TSource>(string s, out TSource source);
    
        public static IEnumerable<TResult> WhereParsed<TSource, TResult>(
                                                   this IEnumerable<TSource> source,
                                                   TryParseDelegate<TResult> tryParse)
        {
            // check arguments against null first
    
            foreach (var item in source)
            {
                TResult result;
                if (tryParse(item.ToString(), out result))
                {
                    yield return result;
                }
            }
        } 
    }
    

    用法:

    var result = marketInputs.Cast<object>()
                             .WhereParsed<object, MarketInput> 
                                         // need to specify explicit,
                                        // out param type cannot be inferred from usage
                                  (ExcelCache.TryGetCache).ToList();
    

    【讨论】:

      【解决方案3】:

      TryParse() 的问题在于它不是任何接口的实现:您要么需要使用反射来查找方法,要么(更简单)只提供一个转换委托。

      然后您可以使用 2D 数组(或者实际上是任意维数的数组:

      string[,] raw = { { "1" , "2" , } ,
                        { "3" , "X" , } ,
                        { "5" , "6" , } ,
                      } ;
      int?[] converted = raw.Cast<string>()
                         .Select( s => {
                           int value ;
                           bool parsed = int.TryParse( s , out value ) ;
                           return parsed ? (int?) value : (int?)null ;
                         })
                         .ToArray()
                         ;
      

      如果你的数组是锯齿状的,你需要多一步:

      string[][] raw = { new string[]{"1","2",} ,
                         new string[]{"3","X",} ,
                         new string[]{"5","6",} ,
                       } ;
      int?[] converted = raw.Cast<string[]>()
                         .SelectMany( s => s )
                         .Select( s => {
                           int  value ;
                           bool parsed = int.TryParse( s , out value ) ;
                           return parsed ? (int?) value : (int?)null ;
                         })
                         .ToArray()
                         ;
      

      举个例子:

      var marketInputColl = new Collection<MarketInput>();
      
      foreach (object o in marketInputs)
      {
        MarketInput mktInput;
        if (ExcelCache.TryGetCache<MarketInput>(o.ToString(), out mktInput))
          marketInputColl.Add(mktInput);
      }
      

      我们可以采取同样的基本方法:

      Collection<MarketInput> collection = new Collection<MarketInput>(
        marketInputs
        .Cast<object>()
        .Select( o => o.ToString() )
        .Select( s => {
          MarketInput v ;
          bool parsed = ExcelCache.TryGetCache<MarketInput>( s , out v ) ;
          return parsed ? v : null ;
        })
        .Where( x => x != null )
        .ToList()
        ) ;
      

      【讨论】:

        猜你喜欢
        • 2015-10-28
        • 2023-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-30
        • 2011-01-28
        相关资源
        最近更新 更多