オブジェクト値を文字列に保存しています。たとえば、
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を介して知ることができます。 Enumsはこれで解析しやすいと思います、例えば、
Type destinationType = info.PropertyType;
Enum.Parse(destinationType, "MyValue");
おそらく最初に試すことは:
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);
}
public T Get<T>(string val)
{
if (!string.IsNullOrWhiteSpace(val))
return (T) TypeDescriptor.GetConverter(typeof (T)).ConvertFromString(val);
else
return default(T);
}
ここに簡単なバージョンがあります:
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;
}
Intとdoubleを認識しますが、それ以外はすべて文字列として返されます。 enumの処理に関する問題は、値がどのenumに属しているかを知る方法がなく、文字列であるかどうかを判断する方法がないことです。その他の問題は、日付/時刻または小数を処理しないことです(それらをdoubleからどのように区別しますか?)など。
次のようにコードを変更する場合:
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 });
}
編集:不足している括弧を追加
これであなたの質問に答えられないことはわかっていますが、 Dapper micro ORM を見たことはありますか?
それは非常に単純で(LINQ to SQLまたはそのため、Entity Frameworkと比較して)、必要なことを行います。
このことを考慮:
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自体は 単一のファイル にパッケージ化されており、伝えられるところによると StackOverflowチームが使用 (LinqからSQLを除いて)。