Dynamiczne parsowanie stringa

0

Witam, mam taką sytuację, że posiadam jakiś tekst (zakładam, że zawsze zgodny) i potrzebuje go prze-parsować na dany typ (int, double itd) i ma być zwrócony jako obiject. Już objaśniam na przykładzie

Type t = MetodaPobierajacaTyp(); - w tym momencie mam funkcję, która dynamicznie pobiera typ, ten typ może być dowolny, int, string, double itd. Potrzebuję wykonać parsowanie na ten typ ze stringa, czyli

**object result = type.Parse(string s). **

Oczywiście taki zabieg nie jest dozwolony, dlatego aktualnie mam metodę, która sprawdza każdy typ po kolei i wykonuje dany zabieg, mniejwięcej wygląda ona tak

object result = ParseText(Type t, string s)

Public object ParseText(Type t, string s)
{
if(t == typeof(Int32))
return int.Parse(s);

if(t == typeof(Decimal))
return decimal.Parse(s);
...
}

Oczywiście liczba będzie ograniczona, ale czy jest jakiś inny sposób, bardziej "dynamiczny" ?

0
userName napisał(a)

WPublic object ParseText(Type t, string s)
{
if(t == typeof(Int32))
return int.Parse(s);

if(t == typeof(Decimal))
return decimal.Parse(s);
...
}

Oczywiście liczba będzie ograniczona, ale czy jest jakiś inny sposób, bardziej "dynamiczny" ?

w 99% to zalezy od tego, jakiego "rodzaju" dynamizmu byś chciał.. męczy Cie if/is Type/else/typ.Parse? użyj reflection. męczy cię return-object? uzyj generics.. meczy Cie w ogole Twoja architektura konwersji? uzyj np. tej .Net'owej, patrz post Massther'a.

zakladajac, ze wolisz zostac przy swojej, proponuje:

private Type[] _cached_argtypes = new [] { typeof(string) }

public static TResult ParseAs<TResult>(this string sometext)
{
    MethodInfo meth = typeof(TResult).GetMethod("Parse", BindingFlags.Public|BindingFlags.Static, null, _cached_argtypes, null);
    if(meth == null)
        throw new ArgumentException(string.Format("Type {0} does not implement static Parse(string) method", typeof(TResult)), "sometext");

    return (TResult)meth.Invoke(null, new object[] {sometext} );
}

.. i potem uzywasz tego mniejwiecej tak:
    string xxx = "1234";
    int a = xxx.ParseAs<int>();
    int b = xxx.ParseAs<double>();
    int c = xxx.ParseAs<decimal>();

komennts:

  • extension metod jest tylko dla wygody, ale nie jest konieczna
  • zamiast getmethod oraz method.invoke, mozna uzyc Type.InvokeMember aby wszystko zalatwic 1 razem, ale zrobilem tak, abys mogl znalezione METH'y sobie zcacheowac w Dictionary<TResult, MethodInfo> i oszczedzic sporo czasu jesli wywolan parseas masz wiele
  • kod w/w szuka metod Parse wg. typu parametru, a potem rzutuje wynik na TResult. To jest absolutne minimum. Warto jeszcze przynajmnije dodac, po znalezeniu pasujacej metody, czy jej returntype jest rzutowalny (lub rowny) TResult'owi i rzucic wyjatkiem z opisem problemu -- ostatecznie przeciez ktos moze napisac class MojaKlasa{ public static string Parse(string); } zamiast public static MojaKlasa Parse(string), prawda?

disclaimer: kod pisalem teraz, w biegu, powinien byc w wiekszosci OK, ale nie recze, nawet go nie probowalem kompilowac. Moze zawierac drobne bledy i sladowe ilości orzeszków ziemnych.

0

Dzięki Wam obu za odp, drugie rozwiązanie jest ciekawe, choć dla mnie idealne jest 1.

1 użytkowników online, w tym zalogowanych: 0, gości: 1