ダウンキャストとアップキャスト


88

私はC#(およびOOP)を初めて使用します。次のようなコードがある場合:

class Employee
{
    // some code
}


class Manager : Employee
{
    //some code
}

質問1:これを行う他のコードがある場合:

   Manager mgr = new Manager();
   Employee emp = (Employee)mgr;

これEmployeeはですがManager、そのようにキャストEmployeeすると、アップキャストしているということですか?

質問2

複数のEmployeeクラスオブジェクトがあり、それらのすべてではなく一部がManager'である場合、可能な場合はどうすればそれらをダウンキャストできますか?


6
アップキャストは、明示的なキャストなしで実行できます。だからEmployee emp= mgr;十分なはずです。
私の脇の下にキスする2014

回答:


93
  1. それは正しいです。これを行うと、employeeオブジェクトにキャストされるため、マネージャー固有のものにはアクセスできなくなります。

  2. ダウンキャスティングとは、基本クラスを取得して、それをより具体的なクラスに変換することです。これは、isと次のような明示的なキャストを使用して実現できます。

    if (employee is Manager)
    {
        Manager m = (Manager)employee;
        //do something with it
    }
    

または次のasような演算子を使用します。

Manager m = (employee as Manager);
if (m != null)
{
    //do something with it
}

不明な点がある場合は、修正させていただきます。


ダウンキャスティングとは何かを知るための例が必要ですか?
user184805 2009年

4
確立された用語を再定義することは避けてください。OOPとC#のコンテキストでの「ボクシング」は、かなり異なることを意味します(=値型オブジェクトを参照にラップする)。また、あなたの例asではis、の代わりに演算子を使用し、その後にキャストを使用することができます(そして使用する必要があります)。
Konrad Rudolph

2
私は最初の点で正直に立っています、そして私はそれをする両方の方法を示すために私の答えの後半を変更しました。
RCIX 2009年

2
最初のステートメント(「... [Managerクラスのインスタンス]を「employee」オブジェクト[..]にキャストすると、マネージャー固有のものにアクセスできないことを意味します」)は完全に正確ではありません。OPの例では、EmployeeにManagerでオーバーライドされる仮想メンバーがある場合、キャストに関係なく、CLRはManager実装を呼び出します。C#のポリモーフィズムに関するMSDNの記事から:「派生クラスが仮想メンバーをオーバーライドすると、そのクラスのインスタンスが基本クラスのインスタンスとしてアクセスされている場合でも、そのメンバーが呼び出されます。」MSDNが提供する例はほとんど同じです。
アントニー2013年

49

(Employee)someInstance型が別の型から派生しているかどうかをコンパイラがコンパイル時に通知できるため、アップキャスト(を使用)は一般に簡単です。

ただし、コンパイラは問題のインスタンスが指定されたタイプであるかどうかを常に認識しているとは限らないため、ダウンキャストは通常、実行時に実行する必要があります。C#は、このために2つの演算子を提供-あるダウンキャストの作品かどうかを伝えている、と真/偽のを返します。そして、としてその試みは、キャストを行うと、正しい型可能な場合、またはnullでない場合はを返します。

従業員がマネージャーであるかどうかをテストするには:

Employee m = new Manager();
Employee e = new Employee();

if(m is Manager) Console.WriteLine("m is a manager");
if(e is Manager) Console.WriteLine("e is a manager");

これも使えます

Employee someEmployee = e  as Manager;
    if(someEmployee  != null) Console.WriteLine("someEmployee (e) is a manager");

Employee someEmployee = m  as Manager;
    if(someEmployee  != null) Console.WriteLine("someEmployee (m) is a manager");

11
  • アップキャストは、サブクラス参照から基本クラス参照を作成する操作です。(サブクラス->スーパークラス)(つまり、マネージャー->従業員)
  • ダウンキャストは、基本クラス参照からサブクラス参照を作成する操作です。(スーパークラス->サブクラス)(つまり、従業員->マネージャー)

あなたの場合

Employee emp = (Employee)mgr; //mgr is Manager

あなたはアップキャストをしています。

アップキャストは、実行時に失敗する可能性があるため、明示的なキャストを必要とするダウンキャストとは異なり、常に成功します(InvalidCastException)。

C#は、この例外がスローされないようにするために2つの演算子を提供しています。

から始まる:

Employee e = new Employee();

最初:

Manager m = e as Manager; // if downcast fails m is null; no exception thrown

2番目:

if (e is Manager){...} // the predicate is false if the downcast is not possible 

警告:アップキャストを実行すると、スーパークラスのメソッド、プロパティなどにのみアクセスできます...


6

各EmployeeオブジェクトがManagerオブジェクトであるかどうかを確認する必要がある場合は、OfTypeメソッドを使用します。

List<Employee> employees = new List<Employee>();

//Code to add some Employee or Manager objects..

var onlyManagers = employees.OfType<Manager>();

foreach (Manager m in onlyManagers) {
  // Do Manager specific thing..
}

2

回答1:はい、それはアップキャスティングと呼ばれていますが、あなたのやり方は現代的なやり方ではありません。アップキャストは暗黙的に実行でき、変換は必要ありません。したがって、Employee emp = mgr;と書くだけです。 アップキャストには十分です。

回答2:Managerクラスのオブジェクトを作成すると、managerは従業員であると言えます。クラスマネージャー:従業員Is-従業員クラスとマネージャークラスの間の関係を示しているため。つまり、すべてのマネージャーは従業員であると言えます。

しかし、Employeeクラスのオブジェクトを作成する場合、クラスEmployeeは他のクラスを継承していないクラスであるため、この従業員がマネージャーであるとは言えません。したがって、そのEmployeeClassオブジェクトをManagerClassオブジェクトに直接ダウンキャストすることはできません。

つまり、従業員クラスオブジェクトからマネージャークラスオブジェクトにダウンキャストする場合は、最初にマネージャークラスのオブジェクトが必要です。次に、それをアップキャストしてから、ダウンキャストできます。


-1

アップキャスティングとダウンキャスティング:

アップキャスティング:派生クラスから基本クラスへのキャストダウンキャスティング:基本クラスから派生クラスへのキャスト

例と同じことを理解しましょう:

次のように定義されている、2つのクラスShapeを私の親クラスとして、Circleを派生クラスとして考えます。

class Shape
{
    public int Width { get; set; }
    public int Height { get; set; }
}

class Circle : Shape
{
    public int Radius { get; set; }
    public bool FillColor { get; set; }
}

アップキャスト:

Shape s = new Shape();

円c = s;

cとsはどちらも同じメモリ位置を参照していますが、どちらも異なるビューを持っています。つまり、「c」参照を使用すると、基本クラスと派生クラスのすべてのプロパティにもアクセスできますが、「s」参照を使用すると、プロパティにアクセスできます。唯一の親クラスの。

アップキャストの実際的な例は、.netフレームワークのすべてのタイプのストリームリーダーの基本クラスであるStreamクラスです。

StreamReaderリーダー= new StreamReader(new FileStreamReader());

ここでは、FileStreamReader()がストレッドレッドにアップキャストされています。

ダウンキャスティング:

形状s = new Circle(); ここで上で説明したように、sのビューは唯一の親です。親と子の両方に対してそれを作成するには、それをダウンキャストする必要があります。

var c =(Circle)s;

ダウンキャスティングの実際的な例は、WPFのボタンクラスです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.