简体   繁体   English

C#类型的方法重载

[英]Method Overloading with Types C#

I was wondering if the following is possible. 我想知道以下是否可能。 Create a class that accepts an anonymous type (string, int, decimal, customObject, etc), then have overloaded methods that do different operations based on the Type. 创建一个接受匿名类型(字符串,整数,十进制,customObject等)的类,然后使用重载的方法根据类型进行不同的操作。 Example

    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    
  }

}

So now I could call the GetName method, and because I already passed in the type when I initialized the object, the correct method is found and executed. 现在,我可以调用GetName方法,并且由于在初始化对象时已经传递了类型,因此可以找到并执行正确的方法。

TestClass foo = new TestClass<int>();

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

Is this possible or am I just dreaming? 这可能还是我只是在做梦?

What you're trying to do is possible like this: 您尝试做的事情可能是这样的:

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

While this is possible, you're kind of defeating the purpose of generics. 尽管这可能的,但您有点违反了泛型的目的。 The point of generics is when the type doesn't matter, so I don't think generics is appropriate in this case. 泛型的一点是当类型并不重要,所以我不认为仿制药是在这种情况下适当的。

"Specialization" is not possible in C# the way it is in C++. 在C#中不可能像在C ++中那样进行“专业化”。 In .NET generics, a generic class or method of <T> must be the same for all possible values of T. This allows the runtime to do an optimization that two different reference types, say TestClass<string> and TestClass<List<int>>, share the same machine language code. 在.NET泛型中,<T>的泛型类或方法对于T的所有可能值必须相同。这允许运行时进行优化,以使两个不同的引用类型(例如TestClass <string>和TestClass <List <int)成为可能。 >>,共享相同的机器语言代码。 (different value types get separate machine code, but you still can't specialize.) (不同的值类型会获得单独的机器代码,但您仍然无法专长。)

I find it sometimes helps to create a generic interface or base class like this: 我发现有时创建这样的通用接口或基类会有所帮助:

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

And do specialization in derived classes: 并对派生类进行专业化处理:

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

Specialization is not possible in C#. 在C#中无法进行专业化。 The closest thing in C# is the following C#中最接近的内容如下

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

The C# compiler will prefer a non-generic method over a generic method. 与泛型方法相比,C#编译器更喜欢非泛型方法。 This means that calling with an int paramater will bind to the int overload vs. the generic one. 这意味着使用int参数的调用将绑定到int重载,而不是泛型。

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

This will bite you though because this does not apply when the method is called generically. 但是,这会伤到您,因为在一般调用该方法时,这并不适用。 In that case it will bind to the generic overload no matter the type. 在那种情况下,无论类型如何,它将绑定到泛型重载。

public void Gotcha<T>(T value) {
  Example.Method(value);
}

Gotcha(42);  // Still calls Example.Method<T>()

No, this is not possible. 不,这是不可能的。 What you are trying to do is similar to template specialization in C++, which is (sadly) not possible in C#. 您尝试做的事情类似于C ++中的模板专业化,这在C#中是(非常)不可能的。

You need to if/else or switch on 您需要if / else或打开

typeof(T)

to invoke specialized implementations. 调用专门的实现。

However, you can constraint the type of T to be either a class (reference Value) or struct (value) or subclass of a certain baseclass like so: 但是,您可以将T的类型限制为某个基类的类(参考值)或struct(值)或子类,如下所示:

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

Would using class extension methods work for you? 使用类扩展方法对您有用吗?

You can essentially add methods to the classes you want, and then you can call it the same way. 您可以从本质上将方法添加到所需的类中,然后可以以相同的方式进行调用。

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

called using: 调用使用:

myString.GetName();

c# doesn't have support for such dispatching. C#不支持这种调度。

and this is not right way for doing method overloading also (Error'TestClass' already defines a member called 'GetName' with the same parameter types) as long as all inside <> is not a part of method signature. 并且这也不是进行方法重载的正确方法(错误'TestClass'已经定义了具有相同参数类型的名为'GetName'的成员),只要内部所有<>都不是方法签名的一部分。

If you need to do type-specific work in your class, then your class is not generic. 如果您需要在类中进行特定于类型的工作,则该类不是通用的。 You should probably make a seperate class for each type you want to handle. 您可能应该为每个要处理的类型创建一个单独的类。 If there is some functionality that does have a proper reason for being generic, you can put it in an common base class. 如果确实有某些功能具有通用性,那么可以将其放在通用的基类中。

An example: 一个例子:

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
}

As BFree mentioned you can do this with an if tree, or more likely a switch statement, but at some point you'll wish you could just write methods and let .Net figure it out, especially if you grow the library of overloads over time. 正如BFree所提到的,您可以使用if树,或者更可能是switch语句来执行此操作,但是在某些时候,您希望您可以编写方法并让.Net弄清楚,尤其是当您随着时间的推移而增加重载库时。

The solution there is reflection, although it is pretty cheap performance-wise in .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;
}

You're basically just telling the Reflection framework to go do that switch statement for you. 基本上,您只是在告诉Reflection框架为您执行该switch语句。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM