C#尝试从类型列表中转换字符串

C#尝试从类型列表中转换字符串,c#,types,casting,C#,Types,Casting,所以我有两个长度相等的列表,一个字符串列表和一个类型列表。因为您希望验证字符串是否可以转换为第二个列表中指定的各自类型。如果这是不可能的,我想抛出一个异常 那么,想象一下这样的情况: var strings=newlist(){“hi”、“123”、“54234423”、“5.1”}; var types=newlist(){typeof(string)、typeof(int)、typeof(long)、typeof(double)}; 所以我想检查一下: hi can be converte

所以我有两个长度相等的列表,一个字符串列表和一个类型列表。因为您希望验证字符串是否可以转换为第二个列表中指定的各自类型。如果这是不可能的,我想抛出一个异常

那么,想象一下这样的情况:

var strings=newlist(){“hi”、“123”、“54234423”、“5.1”};
var types=newlist(){typeof(string)、typeof(int)、typeof(long)、typeof(double)};
所以我想检查一下:

hi can be converted to a string
123 can be converted to an int
542342342424423 can be converted to a long
5.1 can be converted to a double
我想做这样的事情:

for(var索引=0;索引<4;索引++)
{
var str=字符串[索引];
var@type=类型[索引];
//尝试这样的事情
如果(!str为@type)
抛出新异常()
}
但是,这不起作用,因为
@type
不是一个常量表达式。 我不需要强制转换值,只要验证(真/假)它们是否可以转换即可。 如何解决这个问题?

在c语言中,字符串与其类型(例如与javascript相比)并不等价。如果想知道字符串是否可以转换为int,必须调用int.TryParse()并查看是否成功

这意味着您可能无法按预期的方式概括

编辑:

我写了一种通用的方法,只要您可以为可能遇到的每种类型定义一个方法

     var strings = new List<string>(){/* whatever strings */};
     var typeTesters = new List<Func<string, bool>>
     {
         text => int.TryParse(text, out _),
         text => double.TryParse(text, out _),
         text => long.TryParse(text, out _),
     };

     for (var index = 0; index < 4; index++)
     {
         var str = strings[index];
         var tester = typeTesters[index];

         // Attempt something like this
         if (!tester(str))
             throw new Exception();
     }
var strings=newlist(){/*任何字符串*/};
var typeTesters=新列表
{
text=>int.TryParse(text,out u),
text=>double.TryParse(text,out u),
text=>long.TryParse(text,out),
};
对于(var指数=0;指数<4;指数++)
{
var str=字符串[索引];
var测试器=类型测试器[索引];
//尝试这样的事情
如果(!测试仪(str))
抛出新异常();
}

如其他答案所示,您可以使用Convert.ChangeType为每个基本类型提供通用测试,并为自定义类型提供自己的函数。

我希望我正确理解您的查询。你可以利用它来达到这个目的

var strings = new List<string>(){"hi","123","542342342424423","5.1"};
var types = new List<Type>(){typeof(string),typeof(int),typeof(long),typeof(double)};

foreach(var item in strings.Zip(types,(x,y)=> new {Value = x, Type = y }))
{
    Console.WriteLine($"{Convert.ChangeType(item.Value,item.Type)} can be converted to {item.Type}");
}
样本输出

hi can be converted to System.String
123 can be converted to System.Int32
542342342424423 can be converted to System.Int64
5.1 can be converted to System.Double

提醒:这不过是布鲁诺和阿努解决方案的结合

由于我更喜欢使用自己的转换检查器,所以我只做了一个小改动

解决方案:

try {
  var strings = new List<string> () { "hi", "123", "542342342424423", "5.1" };
  var types = new List<Type> () { typeof (string), typeof (int), typeof (long), typeof (double) };
  foreach (var s in strings.Zip (types, (x, y) => new { Value = x, DataType = y }))
    if (!IsValidType (s.DataType.ToString (), s.Value)) throw new Exception ($"{s.DataType} is not a valid type for {s.Value}");
} catch (Exception e) {
  Console.WriteLine (e.ToString ());
}
static bool IsValidType (string data_type, string value) {
  switch (data_type) {
    case "System.Int32": return int.TryParse (value, out _);
    case "System.Int64": return long.TryParse (value, out _);
    case "System.Double": return double.TryParse (value, out _);
    case "System.String": return true;
    default: return false;
  }
}

我很确定有一些通用的方法可以解决这个问题。我无法想象对每种可能的类型都有一个巨大的开关…@BrunoBelmondo我想最好是对所有可能的类型都有一个ValueConverter类。我的意思是,
Convert.ChangeType()
方法适用于原语,但想象一下非原语类型,如
Date
Time
。通常对于C中的复杂类型,我们使用Json。您可以尝试Newtonsoft.JSON。
Convert.ChangeType
可以与
DateTime
一起使用。它适用于实现
IConvertible
@ScottHannen的任何东西。这可能是最佳选择,因此这对于基本类型很好,但对于未直接由Convert.ChangeType处理的类型,它不能通用化。好主意,谢谢你的回答。是的,它对原语很有效,但一旦我们想转换成非原语,问题就出现了。也许转换器类是更好的方法?为什么要使用此功能?它能让你做什么?@mjwills我正在写一个类型检查器,我需要的正是我上面描述的。我得到一个字符串和一个类型,我需要验证该字符串是否可以在所述类型中铸造。您可以通过确定如何使用一个类型来简化此过程。编写一个接受字符串和类型并确定其是否可以转换的方法。如果你能用一个,你也能用多个。但当你编写一个函数时,我猜你会发现问题就出在这里。这听起来没有什么帮助,但这是一种最好的解决问题的方法,首先不要使用它。换句话说,退一步,看看你想要完成什么,然后找到另一种根本不需要完成的方法。所有的目标类型都实现了吗?如果是这样,我会使用
Convert.ChangeType
并完成它。我不会花更多的时间去思考那些你还不需要处理的类型的“如果”会怎样。不要跨越你没有走过的桥。另一个有效的方法:不要检查。只要做转换。如果它不工作,它将抛出异常。如果由于输入无效而引发异常,请捕获它并确保rethrown异常清楚地指示输入无效。否则,您将转换两次—一次是为了确保您可以转换,另一次是为了转换。看起来结果完全一样,为什么要检查两次呢?
static bool IsValidType (string data_type, string value) {
  switch (data_type) {
    case "System.Int32": return int.TryParse (value, out _);
    case "System.Int64": return long.TryParse (value, out _);
    case "System.Double": return double.TryParse (value, out _);
    case "System.String": return true;
    default: return false;
  }
}