优雅的C#方法从bool TryParse <t>(输入,输出T)和输入[,] </t> </t>的函数返回IEnumerable <t>

时间:2014-08-29 18:58:05

标签: c#

是否有一种优雅的方式来构建IEnumerable<T>来自

bool TryParse<T>(Input, out T) 

类型的输入
Input[,]

基本上我有一个输入的2D数组,想在每个输入上调用TryParse,如果TryParse<T>返回true,我会将返回值附加到&#39; out&#39;到IEnumerable<T>

我可以在for循环中轻松完成这项工作,但我想要更优雅的东西。这就是我现在使用的:

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

3 个答案:

答案 0 :(得分:2)

使用LINQ,

out / ref参数并不能很好地发挥作用。你可以做到,但它很乱。最好的选择是使用一个解析工具,它将返回一个可以为null的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);

答案 1 :(得分: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();

答案 2 :(得分:1)

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