Хорошая практика для создания дополнительных методов, которые относятся к Системе. Объект?

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

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), который может быть пустым (не был должен, хотя), так как базовая база данных, к сожалению, очень либеральна со столбцами, которые могут быть пустыми. И сделать мою жизнь немного легче, я придумал те дополнительные методы.

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

Thank you in advance & Best Regards

Христианин

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

9
задан Patrick Karcher 8 April 2010 в 22:58
поделиться

7 ответов

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

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

<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 .

7
ответ дан 4 December 2019 в 09:36
поделиться

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

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

0
ответ дан 4 December 2019 в 09:36
поделиться

Возможно, стоит подумать о добавлении методов расширения в интерфейс 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);
    }
}
2
ответ дан 4 December 2019 в 09:36
поделиться

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

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

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

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

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

5
ответ дан 4 December 2019 в 09:36
поделиться

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

Если вы объедините это с кодом, который следует принципу единой ответственности, вам нужно будет импортировать это пространство имен только в относительно небольшое количество классов.

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

4
ответ дан 4 December 2019 в 09:36
поделиться

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

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


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

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

5
ответ дан 4 December 2019 в 09:36
поделиться

Я знаю, что это не лучшая практика, но в свои проекты мне нравится включать это расширение для преобразования типов данных, оно мне намного проще, чем класс 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>();
-1
ответ дан 4 December 2019 в 09:36
поделиться