【问题标题】:Match List<string> to List<object> using LINQ?使用 LINQ 将 List<string> 与 List<object> 匹配?
【发布时间】:2019-06-16 01:17:14
【问题描述】:

假设我们有一个包含以下值的输入列表(都是字符串):

var listA = new List<string>();
listA.Add("test");
listA.Add("123");
listA.Add("5.7");

我们还得到了第二个列表:

var listB = new List<object>();
listB.Add(typeof(string));
listB.Add(typeof(int));
listB.Add(typeof(float));

我想通过将 ListA 中的所有值与 ListB 中的类型列表进行匹配来验证其格式是否正确。两个列表的长度相同。

如果是,我想获取一个 List 作为返回值,其中 ListA 的所有值都以 ListB 中指定的格式存储。 如果一个转换失败,我希望能够抛出一个自定义异常。像

throw new MyException($"Failed to convert value {valueX} to {type}");

我只能想象一个非常丑陋的解决方案,其中包含 for 循环、大量强制转换/转换和复制。有没有优雅的解决方案?

【问题讨论】:

  • 首先两个列表都有相同的变量,改变它,接下来,你如何将类型映射到值,它正在使用索引,在第 0 个索引处它应该是这种类型,所以第 0 个 - 字符串,第 1 个- 整数,第二个 - 浮点数。还有你创建了什么解决方案,更新它,这样就可以知道你对它的期望是什么
  • 但是 "123""5.7" 仍然是字符串,并且将无法对 typeof(int)typeof(float) 进行任何合理的检查。
  • 你是否需要支持可空类型(即listB.Add(typeof(int?));?我问,因为如果你做这个问题更难。
  • @JoelCoehoorn 这将如何影响此处发布的解决方案?将 123 检查到字符串中的预期行为将失败,对吧?
  • @mjwills 不需要支持可空类型。

标签: c# arrays linq casting


【解决方案1】:

您可以使用 Zip 执行以下操作。

var result = listA.Zip(listB,(value,type)=> 
                        { 
                           try{return Convert.ChangeType(value,(Type)type);} 
                           catch{throw new Exception($"Cannot cast between value {value} to Type {type}");}
                        });

通过在 Zip 中进行转换,可以确保如果列表前面有异常,您不必转换整个列表。

【讨论】:

    【解决方案2】:

    您可以将Zip 列表放在一起,然后使用Convert.ChangeType 方法

    返回一个指定类型的对象,其值等价于 指定对象。

    它会抛出以下类型的异常

    • InvalidCastException 不支持此转换。 - 或 - value 为 null,conversionType 为值类型。 - 或 - 值不 实现 IConvertible 接口。

    • FormatException 值不是conversionType 可识别的格式。

    • OverflowException 值表示一个超出conversionType 范围的数字。

    • ArgumentNullExceptionconversionType 为空。

    示例

    var listA = new List<string> { "test", "123", "5.7" };
    var listB = new List<Type> { typeof(string), typeof(int), typeof(int) };
        
    var combined = listA.Zip(listB, (s, type) => (Value :s, Type:type));
    
    foreach (var item in combined)
    {
       try
       {
          Convert.ChangeType(item.Value, item.Type);
       }
       catch (Exception ex)
       {
          throw new InvalidOperationException($"Failed to cast value {item.Value} to {item.Type}",ex);
       }
    }
    

    Full Demo Here

    旁注:从技术上讲,这不是强制转换本身,而是改变/转换类型

    【讨论】:

    • 边注应该是主注并用大写锁定写;)
    • “从技术上讲,这不是强制转换本身,而是改变/转换类型”在什么情况下会出现问题?
    • @Kyu96 这不是问题 - 只是使用正确的术语。
    【解决方案3】:

    好吧,如果你想避免 forloop 并使用 linq 来做这件事仍然是可能的

    这就是我想要的

    var listA = new List<string>();
        listA.Add("test");
        listA.Add("123");
        listA.Add("5.7");
    
       var listB = new List<Type>();
        listB.Add(typeof(string));
        listB.Add(typeof(int));
        listB.Add(typeof(float));
       var index =-1;
    
    try{
    var newList = listA.Select((x, i)=>  Convert.ChangeType(x, listB[(index = i)])).ToList();
    
    }catch(Exception e){
    
     throw  new Exception("Failed to cast value "+listA[index]+" to "+listB[index]);
    
    }
    

    【讨论】:

      猜你喜欢
      • 2018-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-22
      • 2016-04-08
      • 1970-01-01
      • 2020-11-27
      • 1970-01-01
      相关资源
      最近更新 更多