Я задаюсь вопросом, должен ли я создать дополнительные методы, которые применяются на уровень объектов или должны ли они быть расположены в более низкой точке в иерархии классов. То, что я имею в виду, является чем-то вроде:
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. Я не отмечал его как "субъективный" намеренно.
Нет , это не лучшая практика. Вы хотите применить методы расширения в самой низкой точке . Я считаю, что есть время и место для (почти) всего, но методы расширения 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 .
Помимо уже упомянутых причин, следует иметь в виду, что методы расширения в System.Object
не поддерживаются в VB. (пока переменная статически типизирована как System.Object
и если переменная не имеет статического типа как Object
, вам лучше расширить другой, более конкретный тип).
Причина этого ограничения - обратная совместимость. См. этот вопрос для получения дополнительной информации.
Возможно, стоит подумать о добавлении методов расширения в интерфейс 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);
}
}
Отрывок из книги «Рекомендации по проектированию фреймворка»
Избегайте определения методов расширения в 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)
Обратите внимание, что рекомендации применимы к другим языкам, для которых такая же привязка поведение присутствует или методы расширения не поддерживаются
Загрязнение методов расширения System.Object может быть весьма раздражающим в общем случае, но вы можете поместить эти методы расширения в отдельное пространство имен , чтобы разработчики активно соглашались использовать эти методы.
Если вы объедините это с кодом, который следует принципу единой ответственности, вам нужно будет импортировать это пространство имен только в относительно небольшое количество классов.
При таких обстоятельствах такие методы расширения могут быть приемлемыми.
В Руководстве по разработке фреймворка не рекомендуется этого делать. Однако эти рекомендации предназначены специально для фреймворков, поэтому, если вы сочтете их очень полезными в своем (линейном) бизнес-приложении, сделайте это.
Но имейте в виду, что добавление этих методов расширения к объекту может загромождать IntelliSense и может сбить с толку других разработчиков. Возможно, они не ожидают увидеть эти методы.В этом случае просто используйте старомодные статические методы: -)
NullReferenceException
s. Поскольку метод расширения выглядит как метод экземпляра, мой мозг часто получает прерывание PossibleUseOfNullObject
от парсера исходного кода при чтении такого кода. В этом случае я должен проанализировать, может ли на самом деле произойти NullReferenceException
или нет. Это значительно усложняет чтение кода, потому что меня чаще прерывают.
По этой причине я очень консервативен в использовании методов расширения. Но это не значит, что я не считаю их полезными. Конечно нет! Я даже написал библиотеку для проверки предварительных условий , в которой широко используются методы расширения. Я даже изначально определил методы расширения в System.Object
, когда начал писать эту библиотеку. Однако, поскольку это многоразовая библиотека, которую используют разработчики VB, я решил удалить эти методы расширения в System.Object
.
Я знаю, что это не лучшая практика, но в свои проекты мне нравится включать это расширение для преобразования типов данных, оно мне намного проще, чем класс 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>();