【问题标题】:Using a generic type argument in place of an argument of type System.Type. Is it a smell? [closed]使用泛型类型参数代替 System.Type 类型的参数。是气味吗? [关闭]
【发布时间】:2013-08-15 16:21:07
【问题描述】:

我经常看到(例如在许多模拟库中)使用泛型类型参数代替System.Type 类型参数的方法。我特别谈论泛型类型仅用于typeof(T) 操作的情况(即,在方法中的任何地方都没有使用类型 T 的实例,并且 T 没有用于返回类型或其他参数)。

例如考虑以下方法:

public string GetTypeName(System.Type type) { return type.FullName; }

此方法通常带有通用版本:

public string GetTypeName<T>() { return GetTypeName(typeof(T)); }

问题 这是不好的做法还是好的做法?
这是语法糖还是有更多?

我认为这是滥用语言特性来缩写对接受 System.Type 类型参数的方法的调用

你认为这是一种气味吗?应该避免这种情况吗?或者这实际上是一个好习惯(提供一个通用方法作为避免输入typeof()的快捷方式)。

以下是我能想到的使用这种模式的一些实际问题:

  1. 如果添加了非 System.Type 类型的参数 - 方法 可能 需要重写(如果参数的顺序在语义上很重要)为非泛型版本(否则某些参数将是泛型类型参数,还有一些是常规参数)。
  2. 它需要两种方法(通用和非通用,用于编译时类型未知的情况)。因此添加了几乎没有意义的单元测试。

另一方面,这是一种常见的做法(大多数人总是正确的,对吗?)但更重要的是,当我对需要在编译时已知的 System.Type 类型的单个参数的代码进行提取方法重构时,ReSharper 更喜欢该签名时间(我学会了接受他们的建议,虽然不是出于信心,而是认真地)。

【问题讨论】:

  • A zen koan 基本上 - 类型参数是类型参数吗?这也让我感到厌烦。
  • 这个问题无法明确回答。一个人闻到的味道可能不会被另一个人闻到。该语言支持这两种情况的事实意味着这两种形式在技术上都是有效的实现。

标签: c# coding-style


【解决方案1】:

我认为您需要考虑文档。这些方法的作用有多明显?如果您有两种方法(一种带有Type,另一种带有类型参数),用户需要同时查看并选择。没有查看您的代码的人可能不会意识到第二个代码只是调用了第一个代码。

两者都使用绝对有意义的地方是在实际使用类型参数的情况下,并且对于Type 版本有某种回退。例如:

object GetThingOfType(Type type) { ... }

T GetThingOfType<T>() { return (T)GetThingOfType(typeof(T)); }

要考虑的另一件事:类型参数必须始终显式编写。如果可能对同一个类型对象执行多个操作,则使用类型参数没有帮助。考虑这样的事情:

var t = typeof(string);
var name = GetTypeName(t);
var assemblyName = t.Assembly.FullName;

虽然我知道类型是string,但我不应该在这里写GetTypeName&lt;string&gt;,因为我会重复自己。通过给我一个我通常最好不要选择的选项,你增加了一些不必要的复杂性。

更模糊的一点是 IDE 对 XML 文档的支持。您像这样记录类型参数:

<typeparam name="T">important information</typeparam>

然后如果你在 C# 中输入GetTypeName&lt;,Visual Studio 会显示“T:重要信息”。但是,由于某种原因,当您在 Visual Basic 中键入 GetTypeName(Of 时,它不会(截至 2012 年)。

【讨论】:

    【解决方案2】:

    你是对的:考虑方法的语义。它是在类型的实例上运行,还是在类型本身上运行?

    如果它是在实例上操作,那么它应该是一个泛型方法。如果它在类型上,则将其设为Type 类型的参数。

    所以在你的例子中我会说

    public string GetTypeName(System.Type type) { return type.FullName; }
    

    public static int Count<TSource>(this IEnumerable<TSource> source)
    

    正在对IEnumerable&lt;TSource&gt; 类型的实例source 进行操作。

    总的来说,我看到泛型被滥用多于使用良好。在我看来,任何执行 typeof(T) 或更糟糕的是,使用任何类型的反射的通用方法实现都不是真正的通用方法,而是一种滥用。毕竟,泛型意味着无论类型参数如何,它的工作原理都是一样的,不是吗?

    所以,总而言之,我同意你的看法——它闻起来很香。

    【讨论】:

      【解决方案3】:

      我不使用string GetName&lt;T&gt;() { return typeof(T).Name; } 模式,因为它是设计模式的误用(误用可能很严重,但我想不出正确的词),这是泛型的原因,即:泛型类型参数编译器和 JITter 是否存在(参见this question 的答案),以便它们可以生成特定类型的存储、参数、堆栈变量等。

      使用它作为在运行时将类型参数传递给我的便捷方法,我闻起来很臭。有时typeof(T) 是必要的,但我发现它们很少见,通常只在使用泛型做复杂的事情时才需要,而不是简单的类型安全之类的事情。如果我看到它,我肯定会停下来问自己为什么它在那里。

      【讨论】:

        【解决方案4】:

        正如已经说过的,在我看来,这只是个人喜好问题。根据我的经验,大多数接受 Type 类型参数的方法都可以使用附带的扩展方法在语法上“加糖”。

        因此,在您的示例中,我会将第二种方法作为扩展。使用这种方法,您可以获得第二个问题的解决方案 - 不需要不必要的单元测试。但是,第一个仍然存在;但是,无论如何,添加参数都需要重构,因此它将提供一个机会来更改扩展方法的使用者,以便他们使用原始方法的修改版本。

        当然,这只是个人意见。

        【讨论】:

          【解决方案5】:

          泛型方法比具有Type 类型参数的方法具有优势,因为它可以使用提供的类型引用其他泛型事物。这在以下场景中特别有用:

          public string GetTypeName<T>()
          { 
              return Cache<T>.TypeName;
          }
          
          private static class Cache<T>
          {
              public static readonly TypeName = GetTypeName(typeof(T));
          }
          

          这个缓存很简单,不需要乱用字典,而且它是自动线程安全的。

          话虽这么说,如果实现不使用这种可能性,那么两者之间的区别只是表面上的。

          【讨论】:

            【解决方案6】:

            处理类型的方法通常这样做:处理类型。

            IMO,Class.Method&lt;SomeType&gt;();Class.Method(typeof(SomeType)); 好很多

            但我猜这是见仁见智的问题。

            考虑 LINQ 的 .OfType&lt;T&gt;(),例如:

            personlist.OfType<Employee>().Where(x => x.EmployeeStatus == "Active");
            

            对比:

            personlist.OfType(typeof(Employee)).Where(x => ((Employee)x).EmployeeStatus == "Active");
            

            你更喜欢哪一个?

            【讨论】:

            • OfType 方法的签名是:public static IEnumerable&lt;TResult&gt; OfType&lt;TResult&gt;(this IEnumerable source) 类型参数用于返回类型。如果不将结果减少到IEnumerable&lt;object&gt;,则无法使用 typeof(Employee) 重写此方法。
            • 所以你的意思是这是一个语法糖,它使代码好多更好?
            • @THX-1138 也许这是一个不好的例子,我的目的是展示两种情况下的语法差异
            • 但如果 C# 将类型表达式(例如 Employee)隐式转换为 System.Type 的实例(即,如果需要 System.Type 类型的实例,则将 Employee 转换为 typeof(Employee)) - 那么你更喜欢:Class.Method(SomeType) 而不是 Class.Method()?所以必须输入typeof(...)的问题。 (我同意这是一个有效的论点)
            • @THX-1138 可能,typeof() 的存在只会让它感觉不那么自然。我猜 C# 的真正美妙之处在于与大多数其他语言相比,它给人的感觉是多么自然。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-06-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多