C#泛型字符串解析为任何对象

时间:2010-10-19 06:36:58

标签: c# string parsing generics

我将对象值存储在字符串中,例如,

string[] values = new string[] { "213.4", "10", "hello", "MyValue"};

有没有办法一般初始化适当的对象类型?例如,像

double foo1 = AwesomeFunction(values[0]);
int foo2 = AwesomeFunction(values[1]);
string foo3 = AwesomeFunction(values[2]);
MyEnum foo4 = AwesomeFunction(values[3]);

其中AwesomeFunction是我需要的功能。最终用途是初始化属性,例如,

MyObject obj = new MyObject();
PropertyInfo info = typeof(MyObject).GetProperty("SomeProperty");
info.SetValue(obj, AwesomeFunction("20.53"), null);

我需要这样的功能的原因是我将所述值存储在数据库中,并希望通过查询读出它们,然后初始化对象的相应属性。这有可能吗?整个对象没有存储在数据库中,只是我想阅读的几个字段&动态设置。我知道我可以静态地做到这一点,但是这将变得乏味,难以维护,并且正在阅读许多不同领域/属性的错误。

编辑:如果AwesomeFunction可以使用指定接受字符串的构造函数的自定义类,则可以使用加分点。

EDIT2:在我想要使用此类功能的特定情况下,可以通过PropertyType了解目标类型。我认为枚举很容易解析,例如,

Type destinationType = info.PropertyType;
Enum.Parse(destinationType, "MyValue");

4 个答案:

答案 0 :(得分:36)

也许首先要尝试的是:

object value = Convert.ChangeType(text, info.PropertyType);

但是,这不支持通过自定义类型的可扩展性; 如果你需要,那该怎么样:

TypeConverter tc = TypeDescriptor.GetConverter(info.PropertyType);
object value = tc.ConvertFromString(null, CultureInfo.InvariantCulture, text);
info.SetValue(obj, value, null);

或者:

info.SetValue(obj, AwesomeFunction("20.53", info.PropertyType), null);

public object AwesomeFunction(string text, Type type) {
    TypeConverter tc = TypeDescriptor.GetConverter(type);
    return tc.ConvertFromString(null, CultureInfo.InvariantCulture, text);
}

答案 1 :(得分:4)

public T Get<T>(string val)
{
    if (!string.IsNullOrWhiteSpace(val))
        return (T) TypeDescriptor.GetConverter(typeof (T)).ConvertFromString(val);
    else 
        return default(T);
}

答案 2 :(得分:3)

这是一个简单的版本:

object ConvertToAny(string input)
{
    int i;
    if (int.TryParse(input, out i))
        return i;
    double d;
    if (double.TryParse(input, out d))
        return d;
    return input;
}

它将识别整数和双精度数,但其他所有内容都以字符串形式返回。处理枚举的问题在于,无法知道值属于哪个枚举,并且无法判断它是否应该是字符串。其他问题是它不处理日期/时间或小数(你如何区分它们与双打?)等。

如果您愿意更改代码,请执行以下操作:

PropertyInfo info = typeof(MyObject).GetProperty("SomeProperty"); 
info.SetValue(obj, AwesomeFunction("20.53", info.PropertyType), null); 

然后它变得非常容易:

object ConvertToAny(string input, Type target)
{
    // handle common types
    if (target == typeof(int))
        return int.Parse(input);
    if (target == typeof(double))
        return double.Parse(input);
    ...
    // handle enums
    if (target.BaseType == typeof(Enum))
        return Enum.Parse(target, input);
    // handle anything with a static Parse(string) function
    var parse = target.GetMethod("Parse",
                    System.Reflection.BindingFlags.Static |
                    System.Reflection.BindingFlags.Public,
                    null, new[] { typeof(string) }, null);
    if (parse != null)
        return parse.Invoke(null, new object[] { input });
    // handle types with constructors that take a string
    var constructor = target.GetConstructor(new[] { typeof(string) });
    if (constructor != null)
        return constructor.Invoke(new object[] { input });
}

编辑:添加了缺失的括号

答案 3 :(得分:0)

我知道这不能回答你的问题,但是你看过Dapper micro ORM吗? 这是简单的(与LINQ to SQL相比,或者,出于这个原因,实体框架)并且做你想要的。

考虑一下:

public class Dog
{
    public int? Age { get; set; }
    public Guid Id { get; set; }
    public string Name { get; set; }
    public float? Weight { get; set; }    
}            

var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select * from Dogs where Id = @Id",
    new { Id = 42 }
).First();

Dapper本身打包在single file中,据说是is used by StackOverflow team(除了Linq to SQL)。