Хорошая практика для создания методов расширения, которые применяются к System.Object? - PullRequest
9 голосов
/ 10 марта 2010

Мне интересно, должен ли я создавать методы расширения, которые применяются на уровне объекта, или они должны быть расположены в нижней точке иерархии классов. Я имею в виду что-то вроде:

public static string SafeToString(this Object o) {
    if (o == null || o is System.DBNull)
        return "";
    else {
        if (o is string)
            return (string)o;
        else
            return "";
    }
}

public static int SafeToInt(this Object o) {
    if (o == null || o is System.DBNull)
        return 0;
    else {
        if (o.IsNumeric())
            return Convert.ToInt32(o);
        else
            return 0;
    }
}
//same for double.. etc

Я написал эти методы, поскольку мне приходится много работать с данными базы данных (из OleDbDataReader), которые могут быть нулевыми (хотя не должны), поскольку базовая база данных, к сожалению, очень либеральна со столбцами, может быть нулевым И чтобы облегчить мне жизнь, я разработал эти методы расширения.

Я хотел бы знать, является ли это хорошим стилем, приемлемым стилем или плохим стилем. Меня это беспокоит, потому что это "загрязняет" объектный класс.

Спасибо заранее и с наилучшими пожеланиями:)

Christian

P.S. Я не пометил его как «субъективный» намеренно.

Ответы [ 7 ]

7 голосов
/ 10 марта 2010

Нет , это не очень хорошая практика. Вы хотите применить методы расширения в самой низкой точке . Я считаю, что есть время и место для (почти) всего, но методы расширения System.Object почти никогда не будут подходящими. Вы должны иметь возможность применять методы расширения, такие как этот, гораздо дальше вниз по стеку наследования. В противном случае это загромождает ваш смысл и, возможно, в конечном итоге будет неправильно использоваться другими разработчиками.

Однако методы расширения объектов данных для работы со значениями Null - это очень хорошее использование методов расширения. Подумайте над тем, чтобы поставить их прямо на вас OleDbDataReader . У меня есть общий метод расширения, который называется ValueOrDefault, что. , , хорошо, я просто покажу вам это:

<Extension()> _
Public Function ValueOrDefault(Of T)(ByVal r As DataRow, ByVal fieldName As String) As T
    If r.IsNull(fieldName) Then
        If GetType(T) Is GetType(String) Then
            Return CType(CType("", Object), T)
        Else
            Return Nothing
        End If
    Else
        Return CType(r.Item(fieldName), T)
    End If
End Function

Это VB, но вы понимаете. Эта присоска экономит мне кучу времени и действительно способствует чистому коду при чтении из базы данных. Вы на правильном пути , но ваше чувство заклинания правильное: у вас слишком высокие методы расширения.

Поместить методы расширения в отдельное пространство имен лучше, чем ничего (это вполне допустимое использование пространств имен; это использует Linq), но вам не нужно этого делать. Чтобы эти методы применялись к различным объектам БД, примените методы расширения к IDataRecord .

5 голосов
/ 10 марта 2010

Отрывок из книги «Руководство по проектированию рамок»

Избегайте определения методов расширения на System.Object, если не совсем необходимо. При этом помните что пользователи VB не смогут использовать определенные таким образом методы расширения и, как такие, они не смогут принять Преимущество юзабилити / синтаксиса которые идут с методами расширения.

Это потому, что в VB объявление переменная как объект заставляет весь метод вызовы на нем, чтобы быть поздно связаны - в то время как привязки к методам расширения определяются во время компиляции (рано связанно). Например:

public static class SomeExtensions{
     static void Foo(this object o){…} } … Object o = … o.Foo(); 

В этом примере вызов Foo не будет выполнен в VB. Вместо этого синтаксис VB должен просто будьте: SomeExtensions.Foo (o)
Обратите внимание, что руководство относится к другие языки, где такая же привязка поведение присутствует, или где методы расширения не поддерживаются

5 голосов
/ 10 марта 2010

Руководство по разработке структуры советует вам не делать этого. Тем не менее, эти рекомендации предназначены специально для фреймворков, поэтому, если вы найдете их очень полезными в своем (линейном) бизнес-приложении, сделайте это.

Но учтите, что добавление этих методов расширения к объекту может загромождать IntelliSense и может запутать других разработчиков. Они могут не ожидать увидеть эти методы. В этом случае просто используйте старые статические методы: -)

<ч /> Одна вещь, которую я лично испытываю беспокойство по поводу разбрызгивания методов расширения везде, это то, что мой процессор (мой мозг) обучен, чтобы найти возможные NullReferenceException s. Поскольку метод расширения выглядит как метод экземпляра, мой мозг часто получает прерывание PossibleUseOfNullObject от анализатора исходного кода при чтении такого кода. В этом случае я должен проанализировать, может ли NullReferenceException действительно произойти или нет. Это делает чтение кода намного сложнее, потому что меня чаще прерывают.

По этой причине я очень консервативен в отношении использования методов расширения. Но это не значит, что я не думаю, что они полезны. Конечно нет! Я даже написал библиотеку для проверки предварительных условий , которая широко использует методы расширения. Я даже изначально определил методы расширения на System.Object, когда начал писать эту библиотеку. Однако, поскольку это библиотека многократного использования и используется разработчиками VB, я решил удалить эти методы расширения в System.Object.

4 голосов
/ 10 марта 2010

Загрязнение метода расширения System.Object может быть довольно раздражающим в общем случае, но вы можете поместить эти методы расширения в отдельное пространство имен , так что разработчики должны активно включить использование этих методов.

Если вы сопоставите это с кодом, который следует принципу единой ответственности, вам придется импортировать это пространство имен только в относительно немного классов.

При таких обстоятельствах такие методы расширения могут быть приемлемыми.

2 голосов
/ 10 марта 2010

Возможно, стоит добавить методы расширения в интерфейс IDataRecord? (который реализует ваш OleDbDataReader)

public static class DataRecordExtensions
{
    public static string GetStringSafely(this IDataRecord record, int index)
    {
        if (record.IsDBNull(index))
            return string.Empty;

         return record.GetString(index);            
    }

    public static Guid GetGuidSafely(this IDataRecord record, int index)
    {
        if (record.IsDBNull(index))
            return default(Guid);

        return record.GetGuid(index);
    }

    public static DateTime GetDateTimeSafely(this IDataRecord record, int index)
    {
        if (record.IsDBNull(index))
            return default(DateTime);

        return record.GetDateTime(index);
    }
}
0 голосов
/ 31 марта 2010

Я знаю, что это не лучшая практика, но для моих проектов мне нравится включать это расширение для преобразования типов данных, я нахожу его намного проще, чем класс Convert ..

public static T ChangeType<T>(this object obj) where T : new()
{
    try
    {
        Type type = typeof(T);
        return (T)Convert.ChangeType(obj, type);
    }
    catch
    {
        return new T();
    }
}

Он будет отображаться в каждом объекте, но я обычно просто использую его вместо списка расширений.

Работает так ...

int i = "32".ChangeType<int>();
bool success = "true".ChangeType<bool>();
0 голосов
/ 10 марта 2010

В дополнение к уже упомянутым причинам следует иметь в виду, что методы расширения в System.Object не поддерживаются в VB (если переменная статически типизирована как System.Object и если переменная статически не типизирована как Object вам лучше расширить еще один конкретный тип).

Причиной этого ограничения является обратная совместимость. См. этот вопрос для получения более подробной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...