C#对象的扩展方法

39

在 Object 类上使用扩展方法是一个好主意吗?

我想知道,通过注册此方法,是否会导致性能损失,因为它会加载在上下文中加载的每个对象上。


3
没有性能惩罚,但你会污染每个符号上出现的智能感知选择...对我来说已经太晚进行重构,如果要再做一次选择,我不会再这样做。 (翻译:在代码中添加这些内容不会影响程序的运行效率,但会使得智能感知提示列表变得杂乱无章。由于项目周期已经较晚,我不会再进行重构。如果可以再做一次选择,我不会再这样做。) - Gabriel Magana
6个回答

42

除了其他回答之外:

使用扩展方法不会有性能惩罚,因为它是编译器功能。考虑以下代码:

public static class MyExtensions
{
    public static void MyMethod(this object) { ... }
} 

object obj = new object();
obj.MyMethod();

调用 MyMethod 实际上会被编译为:

MyExtensions.MyMethod(obj);

谢谢,知道这是编译器特性的事实很好。本主题中讨论实现方法的具体范围的其他观点也是非常好的观点。 - Mandrake

15

由于它不会附加到系统中的每种类型,因此不会有性能损失,它只是可用于在系统中调用任何类型。所有将发生的是该方法将显示在每个对象的智能感知中。

问题是:你是否真的需要它在对象上,还是可以更具体一些。如果需要在对象上,则应该为对象而制作。


7
值得注意的是,只有在你已经通过using语句将包含扩展方法的命名空间引入后,它才会在“智能感知中的每个对象”中显示。请注意不改变原意,简化语言。 - Doctor Jones

7

如果您真的想扩展每个对象,那么这样做是正确的。但是,如果您的扩展只适用于某个对象子集,则应将其应用于必要的最高分层级别,但不要超过此范围。

此外,该方法仅在导入您的命名空间的位置可用。

我已经为一个尝试将对象转换为指定类型的方法扩展了Object

public static T TryCast<T>(this object input)
{
    bool success;
    return TryCast<T>(input, out success);
}

我还将其重载以接受一个success布尔值(就像TryParse一样):

public static T TryCast<T>(this object input, out bool success)
{
    success = true;
    if(input is T)
        return (T)input;
    success = false;
    return default(T);
}

我后来将这个扩展到尝试解析input(通过使用ToString和转换器),但这变得更加复杂。


我喜欢那个,你在那里放置了一个try/catch块吗? - Chris Kooken

2

在Object类上使用扩展方法是一个好主意吗?

是的,事实上有些情况下这是一个很棒的主意。在Object类上使用扩展方法不会有任何性能损失。只要你不调用该方法,你的应用程序的性能就不会受到影响。

例如,考虑以下扩展方法,它列出给定对象的所有属性并将其转换为字典:

public static IDictionary<string, object> ObjectToDictionary(object instance)
{
    var dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
    if (instance != null)
    {
        foreach (var descriptor in TypeDescriptor.GetProperties(instance))
        {
            object value = descriptor.GetValue(instance);
            dictionary.Add(descriptor.Name, value);
        }
    }
    return dictionary;
}

0
以下示例演示了扩展方法的使用。
namespace NamespaceName
{
public static class CommonUtil
{
    public static string ListToString(this IList list)
    {
        StringBuilder result = new StringBuilder("");

        if (list.Count > 0)
        {
            result.Append(list[0].ToString());
            for (int i = 1; i < list.Count; i++)
                result.AppendFormat(", {0}", list[i].ToString());
        }
        return result.ToString();
    }
  }
}

以下示例演示了如何使用此方法。
var _list = DataContextORM.ExecuteQuery<string>("Select name from products").ToList();
string result = _list.ListToString();

-1

这是一个老问题,但我没有看到任何答案尝试重用现有的查找函数来查找活动对象。这里有一个简洁的扩展方法,可选地重载以查找非活动对象。

using System.Linq;

namespace UnityEngine {

public static class GameObjectExtensionMethods {

    public static GameObject Find(this GameObject gameObject, string name, 
        bool inactive = false) {

       if (inactive)
          return Resources.FindObjectsOfTypeAll<GameObject>().Where(
             a => a.name == name).FirstOrDefault();
       else
           return GameObject.Find(name);
    }
  }
}

如果您在Update方法中使用此函数,您可能需要考虑使用数组循环遍历来替换LINQ语句,以消除垃圾生成。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接