如何分离双精度和字符串项,得到无效的转换错误

How to segregate double and string items, getting invalid cast error

我有一个 Dictionary<string, object>,它具有 stringdoubleobject 值。现在我想在下面的代码中分离两种值类型。目前我收到 无效的转换错误。如何做到这一点?

namespace ConsoleApp26
{
public class Sample
{
    public string SampleName;
    public Dictionary<string, object> SampleValues;
}

public class SampleDivideBetweenDoubleAndStringValue
{
    public string Name { get; set; }
    public double DoubleValue { get; set; }
    public string StringValue { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        try
        {
            var samples = new Sample
            {
                SampleName = "test",
                SampleValues = new Dictionary<string, object> { 
                    { "t1",  45.08 }, 
                    { "t2", "A String Value" }, 
                    { "t3",  83 } 
                }
            };

            var tuple = GetTuple(samples);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }

        Console.ReadKey();
    }

    private static Tuple<IEnumerable<SampleDivideBetweenDoubleAndStringValue>, IEnumerable<SampleDivideBetweenDoubleAndStringValue>> GetTuple(Sample samples)
    {
        var doubles = (from s in samples.SampleValues
                       select new SampleDivideBetweenDoubleAndStringValue
                       {
                           Name = samples.SampleName,
                           DoubleValue = (double)s.Value
                       });

        var strings = (from s in samples.SampleValues
                       select new SampleDivideBetweenDoubleAndStringValue
                       {
                           Name = samples.SampleName,
                           StringValue = (string)s.Value
                       });

        return new Tuple<
          IEnumerable<SampleDivideBetweenDoubleAndStringValue>, 
          IEnumerable<SampleDivideBetweenDoubleAndStringValue>>(doubles, strings);
    }
}
}

您想要字符串的键:

private static Tuple<IEnumerable<SampleDivideBetweenDoubleAndStringValue>, IEnumerable<SampleDivideBetweenDoubleAndStringValue>> GetTuple(Sample samples)
{
    var doubles = (from s in samples.SampleValues
                   select new SampleDivideBetweenDoubleAndStringValue
                   {
                       Name = samples.SampleName,
                       DoubleValue = (double)s.Value
                   });

    var strings = (from s in samples.SampleValues
                   select new SampleDivideBetweenDoubleAndStringValue
                   {
                       Name = samples.SampleName,
                       StringValue = (string)s.Key
                   });

    return new Tuple<IEnumerable<SampleDivideBetweenDoubleAndStringValue>, IEnumerable<SampleDivideBetweenDoubleAndStringValue>>(doubles, strings);
}

但是您根本不需要强制转换这些值。在 Dictionary 中,键是字符串,值是双精度值,无需转换。

编辑 我没有看到它是 。瓦西里是对的。也许我应该删除我的答案,但在我阅读完整的问题之前,我会教自己不要回答。

您可以使用 Where 方法按类型过滤值,就像那样(我使用了 lambda 语法)

private static Tuple<IEnumerable<SampleDivideBetweenDoubleAndStringValue>, IEnumerable<SampleDivideBetweenDoubleAndStringValue>> GetTuple(Sample samples)
{
    var doubles = samples.SampleValues.Where(s => s.Value is double).Select(s => new SampleDivideBetweenDoubleAndStringValue
    {
        Name = samples.SampleName,
        DoubleValue = (double)s.Value
    });

    var strings = (samples.SampleValues.Where(s => s.Value is string).Select(s => new SampleDivideBetweenDoubleAndStringValue
    {
        Name = samples.SampleName, StringValue = (string) s.Value
    }));

    return new Tuple<IEnumerable<SampleDivideBetweenDoubleAndStringValue>, IEnumerable<SampleDivideBetweenDoubleAndStringValue>>(doubles, strings);
}

对于示例中的查询语法,您可以简单地使用

var doubles = from s in samples.SampleValues
        where s.Value is double
        select new SampleDivideBetweenDoubleAndStringValue
        {
            Name = samples.SampleName,
            DoubleValue = (double)s.Value
        };

var strings = from s in samples.SampleValues
        where s.Value is string
        select new SampleDivideBetweenDoubleAndStringValue
        {
            Name = samples.SampleName,
            StringValue = (string)s.Value
        };

由于 Linq 使用延迟执行,因此只有在迭代 IEnumerable 后才会显示示例中的无效转换异常。 83 值还有一个不清楚的地方,因为它是一个整数

您可以在投射前检查对象的类型:

var doubles = (from s in samples.SampleValues
               where s.Value is double
               select new SampleDivideBetweenDoubleAndStringValue
               {
                   Name = samples.SampleName,
                   DoubleValue = (double)s.Value
               });
// same for `string`

或者您可以使用 as:

var sampleValues = (from s in samples.SampleValues
                    select new SampleDivideBetweenDoubleAndStringValue
                    {
                        Name = samples.SampleName,
                        DoubleValue = s.Value as double? ?? 0,
                        StringValue = s.Value as string
                    });

数据结构的主要问题是你 不仅 stringdouble 还有 int:

  var SampleValues = new Dictionary<string, object> { 
    { "t1",  45.08 },             // boxed double value
    { "t2", "A String Value" },   // string value
    { "t3",  83 },                // <- N.B. this is boxed int (83), not double (83.0) value
  };

Casting boxed int into double throws exception :

  object o = 83;         // int value (83) which is boxed into object

  double d = (double) o; // <- Exception will be thrown here (invalid cast)

请注意,转换 可以:

  object o = 83;

  double d = Convert.ToDouble(o); // d == 83.0

因此您可以尝试过滤掉 String 项然后Convert 所有其余的(doubleint 值) 变成 double;在你的情况下:

  var doubles = samples
    .SampleValues       
    .Where(pair => (pair.Value != null) && !(pair.Value is string)) // not string value
    .Select(pair => new {
       Name  = samples.Name,
       Value = Convert.ToDouble(pair.Value), // which we convert to double
     });

  var strings = samples
    .SampleValues       
    .Where(pair => pair.Value is string)
    .Select(pair => new {
       Name  = samples.Name,
       Value = Convert.ToString(pair.Value),
     });