我有这个简单的代码:(简化)
class Program
{
static void Main(string[] args)
{
var s1 = new Student();
var s2 = new Student();
myGenericClass<Student> Mgc = new myGenericClass<Student>();
Mgc.Eq(s1,s2);
}
}
class myGenericClass<T> where T : Person
{
public void Eq(T t1, T t2)
{
Console.WriteLine(t1.Equals(t2));
}
}
class Person
{
public bool Equals(Person p)
{
return true;
}
}
class Student : Person
{
public bool Equals(Student obj)
{
return true;
}
}
调用的方法是Person's
,这是问题:
myGenericClass
初始化为Student
,因此T为学生。那里还有一个约束:where T : Person
- 这意味着人should be a base class。 (学生确实做到了这一点)
问题:
1)这种行为的原因是否与泛型相关?
2)如果是这样,为什么仍然会运行Person的方法而不是Student?什么阻止它与学生打交道?
编辑,我也看到了这个in the spec
答案 0 :(得分:1)
如果通过“此行为”表示它在Person
上调用方法,则表示不是,这是正常的OOP。
为了让您的代码根据实际使用的T
调用“正确的”方法,您需要在基类中创建该方法virtual
,然后override
在后代:
class Person
{
public virtual bool Equals(Person p)
{
return true;
}
}
class Student : Person
{
public override bool Equals(Person obj)
{
return true;
}
}
但是也要观察其他内容,为了Equals
中的Student
覆盖Person
中的Person
,它还需要一个Person
参数。< / p>
请注意,泛型并不意味着“弄清楚在运行时调用哪个方法”,它仍然是编译器在编译时确定调用哪些方法,并且在编译泛型类时它可以看到的是Student
类,因此无法确定void Main()
{
Base o = new Derived();
o.Test1();
o.Test2();
}
public class Base
{
public void Test1()
{
Debug.WriteLine("Base.Test1");
}
public virtual void Test2()
{
Debug.WriteLine("Base.Test2");
}
}
public class Derived : Base
{
public void Test1()
{
Debug.WriteLine("Derived.Test1");
}
public override void Test2()
{
Debug.WriteLine("Derived.Test2");
}
}
的潜在用法。
您可以使用这个简单的LINQPad程序验证此行为:
Base.Test1
Derived.Test2
输出:
{{1}}
以及此警告(您可能在代码中也有此警告):
警告:'UserQuery.Derived.Test1()'隐藏继承的成员'UserQuery.Base.Test1()'。如果想要隐藏,请使用new关键字。
答案 1 :(得分:0)
myGenericClass<T>.Eq
方法不了解从Person
派生的类;它所知道的只是T
是Person
而Person
有Equals(Person p)
方法。由于方法调用在编译时被解析,因此调用它是Person.Equals(Person p)
,而不管派生类型中声明的更具体的方法。
但是你可以这样做:
class myGenericClass<T> where T : Person, IEquatable<T>
{
public void Eq(T t1, T t2)
{
Console.WriteLine(t1.Equals(t2));
}
}
class Person : IEquatable<Person>
{
public bool Equals(Person p)
{
return true;
}
}
class Student : Person, IEquatable<Student>
{
public bool Equals(Student s)
{
return true;
}
}
在这种情况下,myGenericClass<T>.Eq
将使用Equals
中的IEquatable<T>
方法,最终会调用Student
实现。但是,它要求从Person
继承的所有类都实现IEquatable<T>
。
答案 2 :(得分:0)
要执行您需要的操作,您需要添加如下界面:
static void Main(string[] args)
{
var s1 = new Student();
var s2 = new Student();
myGenericClass<Student> Mgc = new myGenericClass<Student>();
Mgc.Eq(s1, s2);
var p1 = new Person();
var p2 = new Person();
myGenericClass<Person> Pgc = new myGenericClass<Person>();
Pgc.Eq(p1, p2);
}
class myGenericClass<T> where T : IFoo<T>
{
public void Eq(T t1, T t2)
{
Console.WriteLine(t1.Equals(t2));
}
}
interface IFoo<T>
{
bool Equals(T t);
}
class Person : IFoo<Person>
{
public bool Equals(Person p)
{
return true;
}
}
class Student : IFoo<Student>
{
public bool Equals(Student obj)
{
return false;
}
}
这将打印False
然后True
。
我希望这会有所帮助。