【问题标题】:Generic method where T is type1 or type2T 为 type1 或 type2 的通用方法
【发布时间】:2012-01-23 02:00:09
【问题描述】:

有没有办法声明泛型类型为type1 type2的泛型函数?

示例:

public void Foo<T>(T number)
{
}

我可以限制 T 是 int 还是 long

【问题讨论】:

标签: c# .net generics compiler-construction


【解决方案1】:

没有。

这没有意义; T 在方法中不会有任何可用的编译时类型。

相反,您应该创建两个重载方法。

【讨论】:

  • 我认为这很有意义。我有一个代码,如果你传递一个不同的参数,那么 double、decimal、float、int、long 等会刹车。我想在编译时验证这一点。没有意义?
  • @gdoron:从您的角度来看,这是有道理的。从编译器的角度来看,这没有意义,因为T 不是可用的类型。
  • 在这种情况下,编译器可以将T视为type1和type2的公共,其中T没有关系是object...
  • 我认为这是一个合理的问题,如果您在字里行间阅读。似乎他正在要求一个约束,例如where T : number,不幸的是它不存在。不过,这将是一个有意义的结构......
【解决方案2】:

我认为目前这是不可能的。

This question 关于创建数学库的内容涵盖了相同的领域,并包括一些变通方法。

【讨论】:

    【解决方案3】:

    虽然您可以使用generic constraint 来限制每个泛型参数T 的类型,但不幸的是,没有任何方法可以让您在编译时强制执行T 是否为type1 or type2

    也没有任何方法可以在编译时强制您的泛型参数只能是任何原始类型(int、long、double、...)。

    【讨论】:

      【解决方案4】:

      改用重载方法:

      public void Foo(int number)
      {
      } 
      
      public void Foo(long number)
      {
      }
      

      无论如何,您都不能对泛型类型执行算术运算。请注意,您可以将 int 值传递给 long 参数。它将自动转换为long。因此,只有一个带有long 参数的方法就足够了。

      较早的编程语言遵循“只能有一种”的原则。 C# 允许您在同一个类、接口或结构中拥有多个同名的方法。这些方法必须具有不同的签名。这意味着,它们必须具有不同数量的参数或具有不同类型(或两者)的参数。这称为方法重载。

      【讨论】:

      • 我不能为每个数值类型写 20 个方法。这就是泛型应该解决的问题
      • 泛型类型参数不支持算术运算。有关示例,请参阅System.Text.StringBuilder。它为不同类型定义了 20 多个 Append() 重载。
      【解决方案5】:

      我知道这是一个老问题,这并不能完美地回答它,但你可以用一个方法来做到这一点,而不是创建多个,或者使用泛型约束......如果你有 20 种奇怪的类型特别有用检查。

      显然,您不会像使用约束时那样进行编译器类型检查,但这在某些情况下会有所帮助...

      public void MyMethod<T>()
      {
          if (!typeof(T).Equals(typeof(int)) &&
              !typeof(T).Equals(typeof(long)))
                  throw new Exception("T must be int or long");
      
          //your logic here
      }
      

      【讨论】:

        【解决方案6】:

        我也遇到了这个问题,我想我找到了更好的解决方案(假设你的方法的重载版本是不够的):

        混合Type1Type2 没有任何相似之处没有任何意义,因为已经写过。因此,必须为这两种对象类型访问任何方法或属性。为了确保编译器这些方法或属性可用于您的对象,请通过创建接口 MyInterface 并通过 Type1Type2 实现它来分组 Type1Type2

        interface MyInterface {
          void MyCommonMethod();
          bool MyCommonProperty { get; }
        }
        
        class Type1 : MyInterface {
          void MyCommonMethod() {
            // TODO: Implement it for Type1
          }
        
          bool MyCommonProperty {
          get {
            // TODO: Implement it for Type1
          }
          }
        }
        
        class Type2 : MyInterface {
          void MyCommonMethod() {
            // TODO: Implement it for Type2
          }
        
          bool MyCommonProperty {
          get {
            // TODO: Implement it for Type2
          }
          }
        }
        

        现在,要重写您的 Foo 方法以同时接受 Type1Type2,将 T 约束为 MyInterface 对象:

        public void Foo<T>(T number) where T : MyInterface
        {
          throw new NotImplementedException();
        }
        

        我觉得这可能会有所帮助。 :)

        【讨论】:

          【解决方案7】:

          对于 ReferenceType 对象,您可以这样做

          public void DoIt<T>(T someParameter) where T : IMyType
          {
          
          }
          

          ...

          public interface IMyType
          {
          }
          
          public class Type1 : IMyType
          {
          }
          
          public class Type2 : IMyType
          {
          }
          

          对于您的情况,使用 long as 参数无论如何都会将使用限制为 long 和 ints。

          public void DoIt(long someParameter)
          {
          
          }
          

          限制您可以使用的任何值类型(例如:int、double、short、decimal):

          public void DoIt<T>(T someParameter) where T : struct
          {
          
          }
          

          更多信息可以查看官方文档here

          【讨论】:

          • 这仅适用于界面吗?允许基类吗?
          • @liang 是的,您可以使用基类或基抽象类或接口。
          猜你喜欢
          • 2021-03-25
          • 1970-01-01
          • 1970-01-01
          • 2011-04-06
          • 1970-01-01
          • 1970-01-01
          • 2012-11-08
          • 2015-05-28
          • 1970-01-01
          相关资源
          最近更新 更多