我遇到了继承和泛型问题。 这是解释我的问题的代码:
namespace TestApplication
{
public class MyClass<T>
{
private T field;
public MyClass(T field)
{
this.field = field;
}
}
public class MyIntClass : MyClass<int>
{
public MyIntClass(int field)
: base(field)
{
}
}
}
当我尝试做这样的事情时:
MyClass<int> sth = new MyClass<int>(10);
MyIntClass intsth = (MyIntClass) sth;
我收到强制转换异常:无效的强制转换异常。无法将'TestApplication.MyClass`1 [System.Int32]'强制转换为'TestApplication.MyIntClass'。
更有甚者,我无法创建演员:
public static implicit operator MyIntClass(MyClass<int> myClass)
因为:'TestApplication.MyIntClass.implicit运算符TestApplication.MyIntClass(TestApplication.MyClass)':不允许在基类之间进行用户定义的转换
我需要如上所述创建演员表。我不知道为什么我不能从基类类型转换。我怎么解决这个问题? 提前谢谢。
修改
感谢您的回答。 现在我看到我无法从基类转换为派生类,我发现它与泛型没有任何关系。 但为什么我不能从基类创建用户定义的转换?我有一个返回基类的方法。我能够定义一个转换方法,但创建一个转换操作符imho将是一个更好的解决方案。
答案 0 :(得分:12)
如果对象实际上是派生类的类型,则只能从基类强制转换为派生类。我的意思是,您无法将基础(MyClass<int>
)的实例强制转换为MyIntClass
。但是,如果它实际上是MyIntClass
类型存储为MyClass<int>
实例,则可以将其强制转换。
MyClass<int> foo = new MyIntClass();
MyIntClass bar = (MyIntClass)foo; // this works.
假设:
class Base {
int x;
}
class Derived : Base {
int y;
}
Base foo = new Base();
Derived bar = (Derived)foo;
如果允许,bar.y
的价值是多少?
事实上,从Derived
转换为Base
根本不是转换。它只是告诉编译器让类型Base
的变量指向类型为Derived
的对象。有可能因为派生的特征比Base
更多或相同,而在另一种情况下并非如此。
如果能够在基类和派生类之间创建转换运算符,则C#编译器将无法将其与为它们定义的内置关系区分开来。这就是为什么你不能在继承层次结构中创建转换操作符的原因。
答案 1 :(得分:10)
到目前为止,其他答案都是正确的,但我想指出您的示例 nothing 与泛型有关。它相当于:
using System;
class Base {}
class Child : Base {}
class Test
{
static void Main()
{
Base b = new Base();
// This will throw an exception
Child c = (Child) b;
}
}
答案 2 :(得分:2)
在评论中你问:
但是为什么不允许从基类转换?
简单 - 这没有任何意义。考虑一下这个例子:
class BaseClass
{
public int x;
public BaseClass(int StartX)
{
this.x = StartX;
}
}
class ChildClass: BaseClass
{
public int Y;
public BaseClass(int StartX, StartY): base(StartX)
{
this.y = StartY;
}
}
class Program
{
public static void Main()
{
BaseClass B = new BaseClass(3);
ChildClass C = (ChildClass)B;
Console.WriteLine(C.y);
}
}
假设演员工作,你认为这个节目会输出什么?更糟糕的是 - 假设BaseClass
有两个子类 - ChildClassA
和ChildClassB
。你想要这个吗?
ChildClassA A = new ChildClassA(); BaseClass bc =(BaseClass)A; ChildClassB B =(ChildClassB)bc;
这有效地允许将ChildClassA
个实例投射到ChildClassB
- 完全错误。
答案 3 :(得分:0)
正如迈赫达德所说,你不能贬低一个物体。上传是隐含的,因此您无法覆盖它。
对于隐式运算符,您仍然可以在派生类中创建一个构造函数,该构造函数接收类型为baseclass的参数。
如果需要自由转换,请将变量定义为基类,但实例化派生类。
答案 4 :(得分:0)
如前所述,您正在尝试将对象转换为不是从中派生出来的类型。您是否想要这样做:
MyClass<int> sth = new MyIntClass(10);
MyIntClass intsth = (MyIntClass) sth;
答案 5 :(得分:0)
尝试使用别名:
,而不是创建MyIntClassusing MyClass<int> = What.Ever.Namespace.MyIntClass;
现在有效:
MyClass<int> foo = new MyClass<int>();
MyIntClass bar = (MyIntClass)foo;
只需了解在执行using
别名时,您必须在别名类型名称(What.Ever.Namespace)上限定命名空间。
答案 6 :(得分:0)
关于你的第二个问题:
但为什么我不能从基类创建用户定义的转换?
好吧,假设你有这个场景
class Base {
}
class Derived {
public static operator Derived(Base b) { ... }
}
你试图这样做
Base x = new Derived();
Derived y = (Derived)x;
应该调用转换吗?当然不是! x
内的值实际上是Derived
类型,因此转换是直接的,没有转换。但是如果值不是Derived
类型,而是具体的Base
,则必须进行用户定义的转换,否则我们会遇到编译器错误。这一切都没有意义;用户定义的转换在编译时找到,x
的值类型仅在运行时已知。因此,编译器不知道该怎么做 - 调用用户定义的转换或只是转换值...
希望这对你有点意义。
答案 7 :(得分:0)
回答你的上次修改。
此代码已经编译,它只在运行时失败:
MyIntClass intsth =(MyIntClass)sth;
因此,如果明确指出,以下强制转换操作符将是多余的:
public static implicit operator MyIntClass(MyClass myClass)
因此,编译器应该阻止您添加该转换。我认为这个错误可能会让人感到困惑,但我认为如果B是从A派生的话,它只是禁止将B类转换为A类(我觉得这个警告似乎是为了防止任何转换为A,起初)。
如果操作符是隐式的,那也是危险的,因为向下转换总是会失败,所以你必须:
答案 8 :(得分:0)
如果将赋值或转换视为值副本值,则将基类赋值/转换为派生类是有意义的。有什么令人困惑的c#for 新手是做事的不一致方式:
int i = 5; // <- this creates an int.
int j = i; // <- this creates another int and copies the value of i into j.
Object a; // <- this does not create a copy of 'Object', only a reference to one
Object b = new Object(); // <- this actually creates an Object
a = b; // <- this sets the reference to an object a to the reference to an object b.
// both of them reference the same Object. No values were copied.
如果它正在复制值,那么将基类复制到派生类就行了 工作。 C#不像其他语言一样工作。
我认为这可能让你感到困惑。