来自C ++背景,我遇到了基于泛型类型的特定实例的重载问题。以下内容不起作用,因为只生成Foo<T>
类的代码实例,因此在Method
内,this
的类型只是Foo<T>
,不是我希望的Foo<A>
或Foo<B>
。在C ++中,我习惯将模板实例化为唯一类型。
using System.Collections.Generic;
class A
{
// Concrete class
}
class B
{
// Concrete class
}
class Bar
{
public void OverloadedMethod(Foo<A> a) {} // do some A related stuff
public void OverloadedMethod(Foo<B> b) {} // do some B related stuff
public void OverloadedMethod(OtherFoo of) {} // do some other stuff
public void VisitFoo(FooBase fb) { fb.Method(this); }
}
abstract class FooBase
{
public abstract void Method(Bar b);
}
class Foo<T> : FooBase
{
// Class that deals with As and Bs in an identical fashion.
public override void Method(Bar b)
{
// Doesn't compile here
b.OverloadedMethod(this);
}
}
class OtherFoo : FooBase
{
public override void Method(Bar b)
{
b.OverloadedMethod(this);
}
}
class Program
{
static void Main(string[] args)
{
List<FooBase> ListOfFoos = new List<FooBase>();
ListOfFoos.Add(new OtherFoo());
ListOfFoos.Add(new Foo<A>());
ListOfFoos.Add(new Foo<B>());
Bar b = new Bar();
foreach (FooBase fb in ListOfFoos)
b.VisitFoo(fb);
// Hopefully call each of the Bar::Overloaded methods
}
}
有没有办法让这样的东西在C#中工作?我宁愿不必将Foo中的代码复制为我想要用于的每种类型的单独类。
编辑: 希望这更清楚一点。
答案 0 :(得分:3)
我现在有一段真正完整的代码来证明这个问题。 OP注意:请在发布之前尝试编译代码。为了达到这个目的,我必须做很多事情。让其他人尽可能轻松地帮助你是件好事。我还删掉了一堆无用的东西。在这里,OtherFoo并不真正相关,也不是FooBase。
class A {}
class B {}
class Bar
{
public static void OverloadedMethod(Foo<A> a) { }
public static void OverloadedMethod(Foo<B> b) { }
}
class Foo<T>
{
// Class that deals with As and Bs in an identical fashion.
public void Method()
{
// Doesn't compile here
Bar.OverloadedMethod(this);
}
}
是的,这不会编译。你到底想要做什么呢?请记住,重载决策是在编译时执行的,而不是执行时。正如falling888所说,你可以转换并调用适当的重载方法 - 但是你希望编译器选择哪两个重载?您希望它与Foo<string>
而不是Foo<A>
或Foo<B>
有什么关系?
这一切都证明.NET泛型确实与C ++模板有很大不同,当然......
答案 1 :(得分:2)
我没有尝试过,但似乎你应该能够通过制作A&amp; A来实现你想要的。 B可访问(例如,使用非循环访问者模式)。
答案 2 :(得分:1)
这适用于静态情况。处理实例函数会有点复杂。这个post from Jon Skeet可能提供一种处理实例方法的合理方法。
class Program
{
static void Main(string[] args)
{
var testA = new Foo<A>();
testA.Method();
var testB = new Foo<B>();
testB.Method();
Console.ReadLine();
var testString = new Foo<string>(); //Fails
testString.Method();
Console.ReadLine();
}
}
class A { }
class B { }
class Bar
{
public static void OverloadedMethod(Foo<A> a)
{
Console.WriteLine("A");
}
public static void OverloadedMethod(Foo<B> b)
{
Console.WriteLine("B");
}
}
class Foo<T>
{
static Foo()
{
overloaded = (Action<Foo<T>>)Delegate.CreateDelegate(typeof(Action<Foo<T>>), typeof(Bar).GetMethod("OverloadedMethod", new Type[] { typeof(Foo<T>) }));
}
public void Method()
{
overloaded(this);
}
private static readonly Action<Foo<T>> overloaded;
}
答案 3 :(得分:0)
编辑:我不确定您是否可以在尝试时完成此操作。我已经尝试了各种各样的技巧来尝试使其工作,并且无法将其编译。我能做的最好的事情是将方法调用拉到我的Generic类之外。如果您的方法调用在外面,那么您可以专门定义泛型中的T。但是,在方法内部,在编译时,编译器不知道T将是什么,因此它不知道要调用哪个重载方法。我能看到的唯一方法是使用开关来确定T的类型并手动指定要调用的重载。
我能做的最好的就是这个,这不是你想要的,但它可以用于类似的效果:
class Stuff<T>
{
public T value { get; set; }
}
class Program
{
static void DummyFunc(Stuff<int> inst)
{
Console.WriteLine("Stuff<int>: {0}", inst.value.ToString());
}
static void DummyFunc(Stuff<string> inst)
{
Console.WriteLine("Stuff<string>: {0}", inst.value);
}
static void DummyFunc(int value)
{
Console.WriteLine("int: {0}", value.ToString());
}
static void DummyFunc(string value)
{
Console.WriteLine("string: {0}", value);
}
static void Main(string[] args)
{
var a = new Stuff<string>();
a.value = "HelloWorld";
var b = new Stuff<int>();
b.value = 1;
var c = "HelloWorld";
var d = 1;
DummyFunc(a);
DummyFunc(b);
DummyFunc(c);
DummyFunc(d);
}
}
得到了输出:
Stuff<string>: HelloWorld
Stuff<int>: 1
string: HelloWorld
int: 1
我有四个重载函数引用两个引用泛型类(一个用于int,一个用于字符串)和两个引用常规类型(一个用于int,一个用于字符串),这一切都正常...这就是你的意思'之后?
编辑:问题似乎不是调用重载方法,它与你的foreach有关,它试图将列表中的所有项目转换为与第一个相同的类型,以便引用重载方法。第一个不符合该确切定义的项将导致编译失败。
答案 4 :(得分:0)
我希望找到一种更简单的方法来做到这一点但是现在我要用这个:
用这些类替换Foo<T>
类:
abstract class Foo<T> : FooBase
{
// Class that deals with As and Bs in an identical fashion.
}
class Foo_A : Foo<A>
{
public override void Method(Bar b)
{
b.OverloadedMethod(this);
}
}
class Foo_B : Foo<B>
{
public override void Method(Bar b)
{
// Doesn't compile here
b.OverloadedMethod(this);
}
}
将实例化更改为
List<FooBase> ListOfFoos = new List<FooBase>();
ListOfFoos.Add(new OtherFoo());
ListOfFoos.Add(new Foo_A());
ListOfFoos.Add(new Foo_B());
这至少不需要在Foo<T>
中公开代码,只需要我转发构造函数。