C# generic string parse to any object
I am storing object values in strings e.g.,
string[] values = new string[] { "213.4", "10", "hello", "MyValue"};
is there any way to generically initialize the appropriate object types? e.g., something like
double foo1 = AwesomeFunction(values[0]);
int foo2 = AwesomeFunction(values[1]);
string foo3 = AwesomeFunction(values[2]);
MyEnum foo4 = AwesomeFunction(values[3]);
where AwesomeFunction
is the function I need. The ultimate use is to intialize properties e.g.,
MyObject obj = new MyObject();
PropertyInfo info = typeof(MyObject).GetProperty("SomeProperty");
info.SetValue(obj, AwesomeFunction("20.53"), null);
The reason I need such functionality is I am storing said values in a database, and wish to read them out via a query and then initialize the corresponding properties of an object. Is this go开发者_JS百科ing to be possible? The entire object is not being stored in the database, just a few fields which I'd like to read & set dynamically. I know I can do it statically, however that will get tedious, hard to maintain, and prone to mistakes with numerous different fields/properties are being read.
EDIT: Bonus points if AwesomeFunction
can work with custom classes which specify a constructor that takes in a string!
EDIT2: The destination type can be know via the PropertyType, in the specific case where I want to use this type of functionality. I think Enums Would be easy to parse with this e.g.,
Type destinationType = info.PropertyType;
Enum.Parse(destinationType, "MyValue");
Perhaps the first thing to try is:
object value = Convert.ChangeType(text, info.PropertyType);
However, this doesn't support extensibility via custom types; if you need that, how about:
TypeConverter tc = TypeDescriptor.GetConverter(info.PropertyType);
object value = tc.ConvertFromString(null, CultureInfo.InvariantCulture, text);
info.SetValue(obj, value, null);
Or:
info.SetValue(obj, AwesomeFunction("20.53", info.PropertyType), null);
with
public object AwesomeFunction(string text, Type type) {
TypeConverter tc = TypeDescriptor.GetConverter(type);
return tc.ConvertFromString(null, CultureInfo.InvariantCulture, text);
}
public T Get<T>(string val)
{
if (!string.IsNullOrWhiteSpace(val))
return (T) TypeDescriptor.GetConverter(typeof (T)).ConvertFromString(val);
else
return default(T);
}
Here's a simple version:
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;
}
It will recognize ints and doubles, but everything else is returned as a string. The problem with handling enums is that there's no way to know what enum a value belongs to and there's no way to tell whether it should be a string or not. Other problems are that it doesn't handle dates/times or decimals (how would you distinguish them from doubles?), etc.
If you're willing to change your code like this:
PropertyInfo info = typeof(MyObject).GetProperty("SomeProperty");
info.SetValue(obj, AwesomeFunction("20.53", info.PropertyType), null);
Then it becomes substantially easier:
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 });
}
Edit: Added a missing parenthesis
I know this doesn't answer your question, but have you looked at Dapper micro ORM?
It's über-simple (compared to LINQ to SQL or, for that reason, Entity Framework) and does what you want.
Consider this:
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 itself is packaged in a single file and, reportedly, is used by StackOverflow team (apart from Linq to SQL).
精彩评论