我想知道是否应该创建适用于对象级别的扩展方法,或者它们是否应该位于类层次结构中的较低点。我的意思是:
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),这些数据可以为null(不应该),因为底层数据库很遗憾非常这可能是空的。为了让我的生活更轻松,我想出了那些扩展方法。
我想知道的是这是好风格,可接受的风格还是糟糕的风格。我有点担心它,因为它有点“污染”对象类。
提前谢谢你&最诚挚的问候:)
基督教
P.S。我没有故意将其标记为“主观”。
答案 0 :(得分:7)
否,这不是好习惯。您希望在可能的最低点应用扩展方法。我相信(几乎)一切都有时间和地点,但扩展方法 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使用它),但你不应该这样做。要使这些方法适用于各种db对象,请将扩展方法应用于 IDataRecord 。
答案 1 :(得分:5)
Framework Design Guidelines建议您不要这样做。但是,这些指南特别适用于框架,因此如果您发现它在您的(业务线)业务应用程序中非常有用,请执行此操作。
但请注意,在对象上添加这些扩展方法可能会使IntelliSense混乱,并可能使其他开发人员感到困惑。他们可能不希望看到这些方法。在这种情况下,只需使用旧时尚静态方法: - )
<小时/> 有一件事我个人觉得在我的CPU(我的大脑)被训练找到可能的
NullReferenceException
时,到处都在使用扩展方法。因为扩展方法看起来像实例方法,所以在阅读此类代码时,我的大脑通常会通过源代码解析器接收PossibleUseOfNullObject
中断。在这种情况下,我必须分析NullReferenceException
是否真的可以发生。这使得阅读代码变得更加困难,因为我经常被打断。
因此我对使用扩展方法非常保守。但这并不意味着我认为它们没有用。一定不行!我甚至写过广泛使用扩展方法的a library for precondition validation。当我开始编写该库时,我甚至在System.Object
上initially defined extension methods。但是,因为这是一个可重用的库并且由VB开发人员使用,所以我决定在System.Object
上删除这些扩展方法。
答案 2 :(得分:5)
摘自“框架设计指南”一书
避免定义扩展方法 System.Object,除非绝对 必要。这样做时,请注意 VB用户将无法使用 如此定义的扩展方法,和 这样,他们将无法采取 可用性/语法优势的优势 随附扩展方法。
这是因为,在VB中,声明了一个 变量作为对象强制所有方法 对它的调用是迟到的 - 绑定到扩展方法时 是编译时确定的(早期 界)。例如:
public static class SomeExtensions{
static void Foo(this object o){…} } … Object o = … o.Foo();
在此示例中,对Foo的调用将失败 VB。相反,VB语法应该 简单地说:SomeExtensions.Foo(o)
请注意,该指南适用于 其他语言相同的绑定 行为存在,或在哪里 不支持扩展方法
答案 3 :(得分:4)
在一般情况下,System.Object的扩展方法污染可能非常烦人,但您可以将这些扩展方法放在单独的命名空间中,以便开发人员必须主动选择使用这些方法。 / p>
如果您将此与遵循单一责任原则的代码相结合,则只需在相对较少的类中导入此命名空间。
在这种情况下,这种扩展方法可能是可以接受的。
答案 4 :(得分:2)
也许考虑将扩展方法添加到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);
}
}
答案 5 :(得分:0)
除了已经提到的原因之外,应该记住VB中不支持System.Object
上的扩展方法(只要变量静态类型为System.Object
并且变量是变量不是静态类型为Object
你应该更好地扩展另一个更具体的类型。)
此限制的原因是向后兼容性。有关详细信息,请参阅this question。
答案 6 :(得分:-1)
我知道这不是最佳做法,但对于我的项目,我想包含此扩展名以转换数据类型,我发现它比转换类更容易..
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>();