【问题标题】:Method Overloading with Types C#使用类型 C# 的方法重载
【发布时间】:2010-12-09 04:19:04
【问题描述】:

我想知道以下是否可能。创建一个接受匿名类型(string、int、decimal、customObject 等)的类,然后具有基于 Type 执行不同操作的重载方法。示例

    class TestClass<T>
{
  public void GetName<string>()
  {
      //do work knowing that the type is a string    
  }

  public string GetName<int>()
  {
      //do work knowing that the type is an int

  } 

  public string GetName<int>(int addNumber)
  {
      //do work knowing that the type is an int (overloaded)    
  } 

  public string GetName<DateTime>()
  {
      //do work knowing that the type is a DateTime

  } 

  public string GetName<customObject>()
  {
      //do work knowing that the type is a customObject type    
  }

}

所以现在我可以调用GetName方法了,因为我在初始化对象时已经传入了类型,所以找到并执行了正确的方法。

TestClass foo = new TestClass<int>();

//executes the second method because that's the only one with a "int" type
foo.GetName();

这是可能的还是我只是在做梦?

【问题讨论】:

    标签: c# types overloading overload-resolution


    【解决方案1】:

    你想要做的可能是这样的:

    class TestClass<T>
    {
       public string GetName<T>()
       {
          Type typeOfT = typeof(T);
          if(typeOfT == typeof(string))
          {
              //do string stuff
          }
       }
    }
    

    虽然这可能的,但你有点违背泛型的目的。泛型的意义在于类型无关,所以我认为泛型在这种情况下不合适。

    【讨论】:

      【解决方案2】:

      “专业化”在 C# 中不可能像在 C++ 中那样。在 .NET 泛型中, 的泛型类或方法对于 T 的所有可能值都必须相同。这允许运行时对两种不同的引用类型进行优化,例如 TestClass 和 TestClass>,共享相同的机器语言代码。 (不同的值类型有不同的机器码,但还是不能专精。)

      我发现创建这样的通用接口或基类有时会有所帮助:

      abstract class Base<T> {
        public abstract T GetName();
        // any common code goes here that does not require specialization
      }
      

      并在派生类中进行专门化:

      class IntVersion : Base<int> {
        public override int GetName() { return 1; }
        public int GetName(int addNumber) { ... }
      }
      class StringVersion : Base<string> {
        public override string GetName() { return "foo"; }
      }
      class DateTimeVersion : Base<DateTime> {
        public override DateTime GetName() { return DateTime.Now; }
      }
      

      【讨论】:

        【解决方案3】:

        在 C# 中无法进行专业化。 C# 中最接近的内容如下

        public void Example() {
          public static void Method<T>(T value) { ... }
          public static void Method(int value){ ... }
          public static void Method(string) { ... }
        }
        

        C# 编译器会更喜欢非泛型方法而不是泛型方法。这意味着使用 int 参数调用将绑定到 int 重载与泛型重载。

        Example.Method(42);  // Method(int)
        Example.Method(new Class1())  // Method<T>(T)
        

        但这会咬你,因为这不适用于一般调用该方法时。在这种情况下,无论类型如何,它都会绑定到泛型重载。

        public void Gotcha<T>(T value) {
          Example.Method(value);
        }
        
        Gotcha(42);  // Still calls Example.Method<T>()
        

        【讨论】:

          【解决方案4】:

          不,这是不可能的。您正在尝试做的类似于 C++ 中的模板专业化,这在 C# 中(遗憾地)是不可能的。

          你需要 if/else 或打开

          typeof(T)
          

          调用专门的实现。

          但是,您可以将 T 的类型限制为类(引用值)或结构(值)或某个基类的子类,如下所示:

           public Foo<T> DoBar<T>() where T : FooBase;
          

          【讨论】:

            【解决方案5】:

            c# 不支持这种调度。

            这也不是进行方法重载的正确方法(错误'TestClass'已经定义了一个具有相同参数类型的名为'GetName'的成员),只要所有内部不是方法签名的一部分。

            【讨论】:

              【解决方案6】:

              使用类扩展方法对你有用吗?

              你基本上可以为你想要的类添加方法,然后你可以用同样的方式调用它。

              namespace ExtensionMethods
              {
                  public static class MyExtensions
                  {
                      public static int GetName(this String str)
                      {
                          ...
                      }
                  }   
              }
              

              调用使用:

              myString.GetName();
              

              【讨论】:

                【解决方案7】:

                如果你需要在你的类中做特定类型的工作,那么你的类就不是通用的。您可能应该为要处理的每种类型创建一个单独的类。如果某些功能确实有适当的通用理由,您可以将其放在通用基类中。

                一个例子:

                abstract class TestClass<T>
                {
                    public List<T> Items { get; set; }
                
                    // other generic (i.e. non type-specific) code
                }
                
                class IntTestClass : TestClass<int>
                {
                    public string GetName()
                    {
                        // do work knowing that the type is an int
                    }
                
                    // other code specific to the int case
                }
                
                class StringTestClass : TestClass<string>
                {
                    public string GetName()
                    {
                        // do work knowing that the type is a string
                    }
                
                    // other code specific to the string case
                }
                

                【讨论】:

                  【解决方案8】:

                  正如 BFree 提到的,您可以使用 if 树或更可能是 switch 语句来做到这一点,但在某些时候,您会希望您可以只编写方法并让 .Net 解决,尤其是如果您扩展了随着时间的推移过载。

                  解决方案是反射,尽管它在 .Net 中的性能相当便宜:

                  using System.Reflection;
                  ...
                  
                  public string DoSomething(object val)
                  {
                      // Force the concrete type
                      var typeArgs = new Type[] { val.GetType() };
                  
                      // Avoid hard-coding the overloaded method name
                      string methodName = new Func<string, string>(GetName).Method.Name;
                  
                      // Use BindingFlags.NonPublic instead of Public, if protected or private
                      var bindingFlags = BindingFlags.Public | BindingFlags.Instance;
                  
                      var method = this.GetType().GetMethod(
                          methodName, bindingFlags, null, typeArgs, null);
                  
                      string s = (string)method.Invoke(this, new object[] { val });
                  
                      return s;
                  }
                  

                  你基本上只是告诉反射框架去为你做那个 switch 语句。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2023-01-20
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多