7

継承とジェネリックに問題があります。これは私の問題を示すコードです:

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 operator TestApplication.MyIntClass(TestApplication.MyClass)': 基本クラスとの間のユーザー定義の変換は許可されていません

上記のようにキャストを作成する必要があります。基本クラスの型からキャストできない理由がわかりません。どうすればこの問題を解決できますか? 前もって感謝します。

編集

回答ありがとうございます。これで、基本クラスから派生クラスに変換できないことがわかり、ジェネリックとは何の関係もないことがわかりました。しかし、基本クラスからユーザー定義の変換を作成できないのはなぜですか? 基本クラスを返すメソッドがあります。変換方法を定義することはできますが、キャスト演算子 imho を作成する方がより良い解決策になります。

4

9 に答える 9

12

オブジェクトが実際に派生クラスの型である場合にのみ、基本クラスから派生クラスにキャストできます。MyClass<int>つまり、 base( )のインスタンスを にキャストすることはできません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なりますか? 実際、からDerivedBaseの変換は変換ではありません。Basetype の変数が typeのオブジェクトを指すようにコンパイラに指示しているだけDerivedです。派生はそれ以上の機能を持っているため可能ですがBase、逆の場合はそうではありません。

基本クラスと派生クラスの間に変換演算子を作成できた場合、C# コンパイラは、それらに対して定義された組み込みの関係とそれを区別できません。これが、継承階層に沿ってキャスト オペレーターを作成できない理由です。

于 2009-01-11T19:59:02.960 に答える
10

これまでの他の回答は正しいですが、あなたの例はジェネリックとはの関係もないことを指摘したいと思います。これは次と同等です:

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; 
    }
}
于 2009-01-11T20:08:40.257 に答える
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に 2 つの子クラスがあると想像してください -ChildClassAChildClassB. これを機能させたいですか?

ChildClassA A = new ChildClassA(); BaseClass bc = (BaseClass)A; ChildClassB B = (ChildClassB)bc;

ChildClassAこれにより、インスタンスを効果的にキャストできるようになりますChildClassB-完全に間違っています。

于 2009-01-11T20:29:02.587 に答える
0

基本クラスの派生クラスへの代入/変換は、代入または変換を値ごとのコピーと見なす場合に意味があります。初心者のためのc#について混乱しているのは、それが物事を行う一貫性のない方法です:

'int'は'simple'タイプです:

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#は他の言語のようには機能しません。

それがあなたを混乱させるものかもしれないと思います。

于 2009-04-17T16:17:52.420 に答える
0

すでに述べたように、オブジェクトを派生元ではない型にキャストしようとしています。あなたはおそらくこれをしたかったですか:

MyClass<int> sth = new MyIntClass(10);
MyIntClass intsth = (MyIntClass) sth;
于 2009-01-11T20:16:32.003 に答える
0

Mehrdad が述べたように、オブジェクトをダウンキャストすることはできません。アップキャストは暗黙的であるため、上書きすることはできません。

暗黙の演算子に関しては、基本クラス型のパラメーターを受け取る派生クラスでコンストラクターを作成できます。

自由にキャストする必要がある場合は、変数を基本クラスとして定義しますが、派生クラスをインスタンス化します。

于 2009-01-11T20:05:15.333 に答える
0

MyIntClass を作成する代わりに、エイリアスを試してください。

using MyClass<int> = What.Ever.Namespace.MyIntClass;

これは有効になりました:

MyClass<int> foo = new MyClass<int>();
MyIntClass bar = (MyIntClass)foo;

usingエイリアスを作成するときは、エイリアスの型名 (What.Ever.Namespace) で名前空間を修飾する必要があることを理解しておいてください。

于 2009-01-11T20:27:24.867 に答える
0

2番目の質問について:

しかし、基本クラスからユーザー定義の変換を作成できないのはなぜですか?

さて、あなたがこのシナリオを持っているとしましょう

class Base {
}

class Derived {
    public static operator Derived(Base b) { ... }
}

そして、あなたはこれをやろうとしました

Base x = new Derived();
Derived y = (Derived)x;

変換を呼び出す必要がありますか? もちろん違います!内部の値xは実際には typeDerivedであるため、キャストは変換なしで直接行われます。しかし、値が typeDerivedではなく、concreteBaseである場合、ユーザー定義の変換を行う必要があります。そうしないと、コンパイラ エラーが発生するからです。これはすべて意味がありません。ユーザー定義の変換はコンパイル時に検出され、値の型はx実行時にのみわかります。したがって、コンパイラは何をすべきかわかりません-ユーザー定義の変換を呼び出すか、単に値をキャストします...

これがあなたにとって少し意味があることを願っています。

于 2009-01-11T20:41:53.590 に答える