创建适用于 System.Object 的扩展方法的良好做法?

发布于 2024-08-24 09:34:06 字数 806 浏览 17 评论 0原文

我想知道是否应该创建适用于对象级别的扩展方法,或者它们是否应该位于类层次结构中的较低位置。我的意思是这样的:

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.我并不是故意将其标记为“主观”。

I'm wondering whether I should create extension methods that apply on the object level or whether they should be located at a lower point in the class hierarchy. What I mean is something along the lines of:

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

I wrote those methods since I have to deal a lot with database data (From the OleDbDataReader) that can be null (shouldn't, though) since the underlying database is unfortunately very liberal with columns that may be null. And to make my life a little easier, I came up with those extension methods.

What I'd like to know is whether this is good style, acceptable style or bad style. I kinda have my worries about it since it kinda "pollutes" the Object-class.

Thank you in advance & Best Regards :)

Christian

P.S. I didn't tag it as "subjective" intentionally.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

丢了幸福的猪 2024-08-31 09:34:06

,这不是一个好的做法。您希望在尽可能低的点应用扩展方法。我相信(几乎)所有事情都有一个时间和地点,但扩展方法 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

No, that is not good practice. You want to apply extension methods at the lowest possible point. I believe there a time and a place for (almost) everything, but extension methods System.Object would almost never be appropriate. You should be able to apply extension methods such as this much further down the inheritance stack. Otherwise it will clutter your intellisense and probably end up being used/depended-upon incorrectly by other developers.

However, extension methods for data objects for dealing with Null values is a very good use of extension methods. Consider putting them right on you OleDbDataReader. I have a generic extension method called ValueOrDefault that . . . well, I'll just show it to you:

<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

That's VB, but you get the picture. This sucker saves me a ton of time and really makes for clean code when reading out of a datarow. You are on the right track, but your sense of spell is correct: you have the extension methods too high.

Putting the extension methods into a separate namespace is better than nothing (this is a perfectly valid use of namespaces; Linq uses this), but you shouldn't have to. To make these methods apply to various db objects, apply the extension methods to IDataRecord.

三生殊途 2024-08-31 09:34:06

在一般情况下,System.Object 的扩展方法污染可能非常烦人,但您可以将这些扩展方法放置在单独的命名空间中,以便开发人员必须主动选择使用这些方法。

如果将此与遵循单一职责原则的代码结合起来,则只需在相对较少的类中导入此命名空间。

在这种情况下,这样的扩展方法可能是可以接受的。

Extension method pollution of System.Object can be quite annoying in the general case, but you can place these extension methods in a separate namespace so that developers must actively opt in to use those methods.

If you couple this with code that follows the Single Responsibility Principle, you should only have to import this namespace in relatively few classes.

Under such circumstances, such extension methods may be acceptable.

未央 2024-08-31 09:34:06

摘自《框架设计指南》一书

避免定义扩展方法
System.Object,除非绝对
必要的。这样做时,请注意
VB 用户将无法使用
由此定义的扩展方法,如
这样,他们将无法采取
可用性/语法优势
带有扩展方法。

这是因为,在 VB 中,声明一个
变量作为对象强制所有方法
对它的调用将被延迟绑定 –
while 绑定到扩展方法
是编译时确定的(早期
边界)。例如:

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

在此示例中,对 Foo 的调用将失败
VB。相反,VB 语法应该
只是:SomeExtensions.Foo(o)
请注意,该指南适用于
具有相同绑定的其他语言
行为存在,或者在哪里
不支持扩展方法

An excerpt from the book "Framework design guidelines"

Avoid defining extension methods on
System.Object, unless absolutely
necessary. When doing so, be aware
that VB users will not be able to use
thus-defined extension methods and, as
such, they will not be able to take
advantage of usability/syntax benefits
that come with extension methods.

This is because, in VB, declaring a
variable as object forces all method
invocations on it to be late bound –
while bindings to extension methods
are compile-time determined (early
bound). For example:

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

In this example, the call to Foo will fail in
VB. Instead, the VB syntax should
simply be: SomeExtensions.Foo(o)
Note that the guideline applies to
other languages where the same binding
behavior is present, or where
extension methods are not supported

醉殇 2024-08-31 09:34:06

框架设计指南建议您不要这样做。但是,这些指南特别适用于框架,因此如果您发现它在您的(行业)业务应用程序中非常有用,请这样做。

但请注意,在对象上添加这些扩展方法可能会使 IntelliSense 混乱,并可能使其他开发人员感到困惑。他们可能不希望看到这些方法。在这种情况下,只需使用旧式静态方法:-)


One thing I personally find troubling about sprinkling extension methods everywhere it that my CPU (my brain) is trained to find possible `NullReferenceException`s. Because an extension method looks like an instance method, my brain often receives a `PossibleUseOfNullObject` interrupt by the *source code parser* when reading such code. In that case I have to analyze whether a `NullReferenceException` can actually occur or not. This makes reading through the code much harder, because I'm interrupted more often.

因此,我对使用扩展方法非常保守。但这并不意味着我认为它们没有用。天啊不!我什至编写了广泛使用扩展方法的用于前提条件验证的库。我什至在 System.Object最初定义的扩展方法 > 当我开始编写那个库时。然而,因为这是一个可重用的库并且由 VB 开发人员使用,所以我决定删除 System.Object 上的这些扩展方法。

The Framework Design Guidelines advice you not to do this. However, these guidelines are especially for frameworks, so if you find it very useful in your (line of) business application, please do so.

But please be aware that adding these extension methods on object might clutter IntelliSense and might confuse other developers. They might not expect to see those methods. In this case, just use old fashion static methods :-)


One thing I personally find troubling about sprinkling extension methods everywhere it that my CPU (my brain) is trained to find possible `NullReferenceException`s. Because an extension method looks like an instance method, my brain often receives a `PossibleUseOfNullObject` interrupt by the *source code parser* when reading such code. In that case I have to analyze whether a `NullReferenceException` can actually occur or not. This makes reading through the code much harder, because I'm interrupted more often.

For this reason I’m very conservative about using extension methods. But this doesn’t mean I don’t think they’re useful. Hell no! I've even written a library for precondition validation that uses extension methods extensively. I even initially defined extension methods on System.Object when I started writing that library. However, because this is a reusable library and is used by VB developers I decided to remove these extension methods on System.Object.

凹づ凸ル 2024-08-31 09:34:06

也许考虑将扩展方法添加到 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);
    }
}

Perhaps consider adding the extension methods to the IDataRecord interface? (which your OleDbDataReader implements)

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);
    }
}
流年里的时光 2024-08-31 09:34:06

我知道这不是最佳实践,但对于我的项目,我喜欢包含这个用于转换数据类型的扩展,我发现它比 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>();

I know its not best practice, but for my projects I like to include this extension for converting data types, i find it much easier than the Convert class..

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();
    }
}

It'll show up in every object but i usually just use this one instead of having a list of extensions..

Works like this...

int i = "32".ChangeType<int>();
bool success = "true".ChangeType<bool>();
左耳近心 2024-08-31 09:34:06

除了已经提到的原因之外,还应该记住,VB 中不支持 System.Object 上的扩展方法(只要变量静态类型为 System.Object< /code> 并且如果变量不是静态类型为 Object 你应该更好地扩展另一个更具体的类型)。

造成此限制的原因是向后兼容性。请参阅此问题 了解更多详情。

In addition to the reasons already mentioned, it should be borne in mind that extension methods on System.Object are not supported in VB (as long as the variable is statically typed as System.Object and if the variable is not statically typed as Object you should better extend another more specific type).

The reason for this limitation is backward compatibility. See this question for further details.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文