Ці ёсць больш генеріков-й спосаб зрабіць гэты тып паводзінаў?

Мы робім шмат упакоўкі і распакавання з DataRow . Так, мы павінны выкарыстоўваць ОРМ, але да таго часу, гэта не тое, што ў нас ёсць. У выніку гэтага, ёсць шмат кода, які выглядае наступным чынам:

string username;

var temp = dr["Username"];
if (DbNull.Equals (temp))
{
    username = "Anonymous";
} else {
    username = dr["Username"].ToString();
}

У рэшце рэшт, гэта стала ўзорам і быў пераведзены на дапаможныя метады:

string username = StringExtensions.SafeParse (dr["Username"], "Anonymous");

This is still cumbersome, and required extension methods for all kinds of primitives. It also clutters up the code. I created a generic extension method, on object, called As. Usage looks like:

string username = dr["Username"].As ("Anonymous");

Гэта адносна простае змяненне было сустрэта з вялікім апломбам з іншымі распрацоўшчыкамі, і прывыкае ў вялікай колькасці месцаў. Частку я незадаволены патэнцыйныя наступствы прадукцыйнасці. <Моцны> Зараз, я ведаю, не заўчаснай аптымізацыі . Я вызначана напісаў код без заўчаснай аптымізацыі, і гэта досыць інкапсулюецца, што аптымізацыя яго пасля не павінна быць вялікім справай. Я пратэставаныя спосаб рабіць два з паловай мільёны пераходаў у секунду на маім адносна сціплай 2ГГц працоўнай станцыі, і я павінен прызнаць, што гэта фенаменальная прадукцыйнасць, у параўнанні з часам яна захоўвае іншыя УБС і чытальнасць імпульс, мы атрымліваем. Аднак, улічваючы прыклад кода ніжэй, я адчуваю, як я злоўжываючы асаблівасць мовы, і гэта можна было б зрабіць значна лепш. Метад xmldoc'ed з «ТУТ БЫЦЬ Цмокі» для заклікаюць гучна! Я шукаю лепшы спосаб пазбегнуць падвойнага бокса. Фактычная версія, якую я для сцісласці апускаю, на самай справе выкарыстоўвае TryParse ў многіх выпадках.

public static TDestination As<tdestination> (this object source, TDestination defaultValue = default(TDestination))
{
    if (source is TDestination)
        return (TDestination) source;

    if (source == null || DbNull.Equals(source))
        return defaultValue;

    if (TDestination is int)
        return (TDestination) (object) Convert.ToInt32 (source.ToString ());

    if (TDestination is long)
        return (TDestination) (object) Convert.ToInt64 (source.ToString ());

    if (TDestination is short)
        return (TDestination) (object) Convert.ToInt16 (source.ToString ());

   //and so on...
}
3
Ваш Як <tdestination> ўзор кода не кампілюецца.
дададзена аўтар phoog, крыніца

5 адказы

Чаму б не праверыць, калі ваш аб'ект IConvertible, і, калі ён ёсць, выкарыстоўваць ToType:

var convertible = source as IConvertible;
if (convertible != null)
    return (TDestination)convertible.ToType(typeof(TDestination), Thread.CurrentThread.CurrentUICulture);
3
дададзена
Оооо Мне гэта падабаецца.
дададзена аўтар Bryan Boettcher, крыніца

На прыкладзе Як метад, паказаным у вашым пытанні, вы можаце проста зрабіць гэта замест таго, каб:

public static TDestination As<tdestination>
    (this object source, TDestination defaultValue = default(TDestination))
{
    if ((source == null) || Convert.IsDBNull(source))
        return defaultValue;

    return (TDestination)source;
}
3
дададзена
@insta: Не, гэта не так. Але ваш уласны Як метад робіць , калі (крыніца ИНТ) праверыць перад выклікам Convert.ToInt32 , і робіць калі (крыніца доўгая) праверыць перад выклікам Convert.ToInt64 , і г.д. Калі вы ўжо ведаеце, што крыніца з'яўляецца боксіровал Int то выклік < код> ToString затым Convert.ToInt32 вынікаюць бокс прывядзенне да аб'екта проста дае вам менавіта тое, што вы пачалі з - коробчатый Int - які затым прыводзіцца да TDestination . (Сапраўды гэтак жа з доўгай , кароткі і г.д.) Так чаму б не толькі пазбегнуць бессэнсоўнага туды-зваротна і прывядзенне да TDestination напрамую?
дададзена аўтар LukeH, крыніца
прамой кідок як гэта робіць Ці любыя паводзіны пераўтварэнні ці гэта проста спадзявацца на няяўным?
дададзена аўтар Bryan Boettcher, крыніца
аб хрыстос гэта таму, што я аблажаўся пытанне. Мой код фактычна правярае TYPEOF (TDestination) не крыніца, які змяняе гульню няшмат.
дададзена аўтар Bryan Boettcher, крыніца

Whenever i goes into reflection or checking the T of my generic class i'm going to use a dictionary Dictionary. As value i always put something in that should be done for each time as Func or Action. In your case i would write it maybe in that way:

public static class MyConverter
{
    private static Dictionary> _MyConverter;

    static MyConverter()
    {
        _MyConverter = new Dictionary>();

       //Use the Add() method to include a lambda with the proper signature.
        _MyConverter.Add(typeof(int), (source) => Convert.ToInt32 (source.ToString()));

       //Use the index operator to include a lambda with the proper signature.
        _MyConverter[typeof(double)] = (source) => Convert.ToDouble(source.ToString());

       //Use the Add() method to include a more complex lambda using curly braces.
        _MyConverter.Add(typeof(decimal), (source) =>
        {
            return Convert.ToDecimal(source.ToString());
        });

       //Use the index operator to include a function with the proper signature.
        _MyConverter[typeof(float)] = MySpecialConverterFunctionForFloat;
    }

   //A function that does some more complex conversion which is simply unreadable as lambda.
    private static object MySpecialConverterFunctionForFloat(object source)
    {
        var something = source as float?;

        if (something != null
            && something.HasValue)
        {
            return something.Value;
        }

        return 0;
    }

    public static TDestination As<tdestination>(this object source, TDestination defaultValue = default(TDestination))
    {
       //Do some parameter checking (if needed).
        if (source == null)
            throw new ArgumentNullException("source");

       //The fast-path exit.
        if (source.GetType().IsAssignableFrom(typeof(TDestination)))
            return (TDestination)source;

        Func func;

       //Check if a converter is available.
        if (_MyConverter.TryGetValue(typeof(TDestination), out func))
        {
           //Call it and return the result.
            return (TDestination)func(source);
        }

       //Nothing found, so return the wished default.
        return defaultValue;
    }
}

Адзіны недахоп такога падыходу, што выкарыстанне аб'екта прыводзіць да (не) боксе, які, магчыма, робіць нейкія праблемы з прадукцыйнасцю, калі функцыя выклікаецца паўторна для часта ў вельмі кароткі прамежак часу. Але, як заўсёды мера да падачы заявы .

З іншага боку, гэта даволі лёгка дадаць дадатковы канвэртар і вы будзеце заўсёды O (1) у сувязі з выкарыстаннем слоўніка.

2
дададзена
Гэта выглядае дзіўным. У вас ёсць доступ да Visual Studio, каб праверыць гэта? Я выявіў праблемы з канструктарам, так як ён не ведае аб TDestination затым. Перасоўванне ініцыялізацыі слоўніка ў як сам метад, здаецца, паражэнне мэты кэшавання :(
дададзена аўтар Bryan Boettcher, крыніца

Як аб вызначэнні метады пашырэння для DataRow поля уласнасці, дзе вы можаце паставіць ўласнае нулявое значэнне таго ж тыпу, што і поле, напрыклад, так:

        public static T Field(this DataRow row, string columnName, T nullValue) { return !row.IsNull(columnName) ? row.Field(columnName) : nullValue; }
0
дададзена

Я згодны, што робіш змена функцыі поля з'яўляецца лепшым спосабам пайсці, але калі вы турбуецеся аб прадукцыйнасці, то не выкарыстоўвайце IsNull() ці фактычная функцыю поля, паколькі яны выконваюць мноства залішніх праверак. Наступны метад усё, што вам сапраўды трэба.

public static T Field(this DataRow row, string columnName, T nullValue)
{
  object value = row[columnName];
  return ((DBNull.Value == value) ? nullValue : (T)value);
}

Гэта ліквідуе неабходнасць у дадатковым боксе адбыцца, і калі вы будзеце асцярожныя з тым, як вы выкарыстоўваеце параметр nullValue вы можаце наогул адмовіцца ад таго, каб паказаць T відавочна пры выкліку функцыі. бяспройгрышная.

0
дададзена
Метад пашырэння не з'яўляецца спецыфічным для DataRow, хоць, гэта проста найбольш агульнае выкарыстанне гэтага. Мы таксама выкарыстоўваць яго ў якасці адліўкі агульнага прызначэння і спосабу пераўтварэння дадзеных.
дададзена аўтар Bryan Boettcher, крыніца
У гэтым выпадку статычны метад канструктар згадвалася раней ваш самы гнуткае рашэнне. Але гэта адбываецца ў даволі цане. Калі вы сапраўды занепакоеныя прадукцыйнасці вы павінны разгледзець стварэнне спецыялізаваных AS функцый, як адзін я падаў для найбольш распаўсюджаных выпадкаў. Такім чынам, яны могуць быць аптымізаваныя як мага.
дададзена аўтар 0rigin, крыніца