C# 类型的方法重载

发布于 2024-08-08 19:38:08 字数 940 浏览 3 评论 0 原文

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

    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();

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

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. 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.

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

娇柔作态 2024-08-15 19:38:08

您尝试做的事情是可能的,如下所示:

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

虽然这是可能的,但您有点违背了泛型的目的。泛型的要点是当类型不重要时,所以我认为泛型在这种情况下不合适。

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.

冷…雨湿花 2024-08-15 19:38:08

“专业化”在 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; }
}

"Specialization" is not possible in C# the way it is in 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. (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; }
}
乜一 2024-08-15 19:38:08

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>()

Specialization is not possible in C#. The closest thing in C# is the following

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. This means that calling with an int paramater will bind to the int overload vs. the generic one.

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>()
蒗幽 2024-08-15 19:38:08

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

您需要 if/else 或 switch on

typeof(T)

来调用专门的实现。

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

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

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#.

You need to if/else or switch on

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:

 public Foo<T> DoBar<T>() where T : FooBase;
柠檬 2024-08-15 19:38:08

c# 不支持此类调度。

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

c# doesn't have support for such dispatching.

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.

情丝乱 2024-08-15 19:38:08

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

您本质上可以向所需的类添加方法,然后可以以相同的方式调用它。

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

调用使用:

myString.GetName();

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();
拥抱影子 2024-08-15 19:38:08

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

一个例子:

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
}

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
}
流心雨 2024-08-15 19:38:08

正如 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 语句。

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.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文