2017-06-11 13 views
1

キャストでこのシナリオを理解するのに苦労しています。C#の基底クラスへの派生クラスのアップキャスト

class Program 
    { 
     static void Main() 
     { 
      IFoo iFoo = GetIFoo(); 
      Foo foo = (Foo)iFoo; 

      //the GetType ext method is executed and it returns Bar 
      if(foo is Foo) 
       Console.WriteLine($"foo is of type: {foo.GetType()}"); 

      Console.ReadLine(); 
     } 

     static IFoo GetIFoo() 
     { 
      var bar = new Bar 
      { 
       Name = "MyName", 
       Surname = "MySurname" 
      } 
      return bar; 
     } 
    } 

質問です:私はバーを作成していていても、私はIFooを返す静的メソッドを作成し、私の主な方法で、

public interface IFoo {} 
    public class Foo : IFoo 
    { 
      public string Name { get; set; } 
    } 
    public class Bar : Foo 
    { 
      public string Surname { get; set; } 
    } 

今:デモ目的のために は、私はこれらのクラスを作成しましたGetIFooメソッドでIFooをFooにキャストしようとすると、fooのタイプはBarでFooではないのはなぜですか?

答えて

2

なぜそれが私がFooiFooをキャストしていた場合、fooのタイプはBarないFooであるということですか?

これは、キャスティングが静的タイプを変更するためです。ダイナミックタイプには影響しません。 fooスタティックタイプはFooですが、ダイナミックタイプはBarです。

各変数は、コンパイラに知られているタイプ(静的タイプ)とランタイムに知られているタイプ(ダイナミック型)を有しています。場合によっては、これらの2つのタイプは同じですが、常に同じである必要はありません。

静的型は、変数の宣言された型です。動的型は、オブジェクトがその変数に割り当てられた後にGetTypeを呼び出すことによって得られるものです。

変数の静的型がその動的型と一致しない場合の例を作成しました。iFooは静的型がIFooですが、その動的型はBarです。BarIFooと互換性があり、インターフェイスを実装しているため、Fooも実装されているため、これは完全に問題ありません。そのためラインと

+0

実行時に動的タイプのBarをFooにキャストすることは可能ですか? – allencage

+0

ありがとう、私は私のコメントに対する答えを見つけました。これはまさに私が理解しようとしていたものです。 – allencage

1

これは本当にinheritance 101次のとおりです。作成したオブジェクトがBar鋳造であるだけで、それが本当に何であるか、どのようにビューそれをない影響を与えます。ここで

あなたはIFooとして表示:

IFoo iFoo = GetIFoo(); 

そして、ここで、あなたは故意Fooとしてそれを見ます。それはFoo、またはその子孫ではありませんでした。実行時にはInvalidCastExceptionになります。

Foo foo = (Foo)iFoo; 

Barインスタンスが合法BarFoo、及びIFoo(及び完全を期すためObjectなど)などで加工することができます。インスタンスの表示方法にかかわらず、それはBarのままです。

+1

Fooオブジェクトを取得する唯一の方法は、具体的にインスタンス化し、別のオブジェクトから必要なプロパティを取得するコンストラクタを持つことです。 – allencage

+0

@allencageはい。キャスト*は、オブジェクトの実際の型を変更(変換)しません。 'Bar'のようにインスタンス化すると、' Bar'のままです。 –

1

Type.GetTypeは、どのタイプの変数を保持していても、基礎となるインスタンスのタイプ(つまり、newの後に指定するタイプ)を提供します。また、foo is Fooは、実際のインスタンスがFooである場合だけでなく、Fooから派生するすべてのタイプについて、trueを与えます。

0

Foo foo = (Foo) iFoo; 

あなたがない変換を行います。BarFooと同時にIFooすべてです。したがって、(Foo)にキャストすると、C#インタープリタはiFooBarであることに気付くため、オブジェクトは変更されません。要は、fooは実際にFooオブジェクトであるとコンパイラは想定していますが、それはFooクラスを拡張する任意のクラスである可能性があります。

のは、次の例とそれがより明確にしてみましょう:

interface IDriveable {} // IFoo 
class Car : IDriveable { // Foo 
    string Name {get; set; } 
} 
class Volkswagen : Car { // Bar 
    bool CorrectPolution { get; set; } 
} 

を今、あなたはVolkswagenが、10は明らかにそれがCarIDriveableで構築する場合。しかし、と言って:Car car = (Car) volkswagen;ではなく、carCarというオブジェクトであることをコンパイラに知らせるだけです。

1

GetType()オブジェクトの戻り値の型。抽象クラスを派生クラスから基本クラスにキャストするときに、新しいインスタンスを作成しなかった場合、既存のオブジェクトに対して新しい型付き参照のみが作成されます。あなたは以下のコードでそれを見ることができます:あなたは、オブジェクトの実行時の型とそのコンパイル時の型の間で混乱している

IFoo iFoo = GetIFoo(); 
Foo foo = (Foo)iFoo; 
Console.WriteLine(ifoo.Equals(foo)); 
1

。上記の行で

IFoo iFoo = GetIFoo(); 

iFooのランタイム型は依然としてBarあります。これはオブジェクトの実際の型です。しかし、タイプIFooの参照を介してBarオブジェクトにアクセスする場合、コンパイラはタイプがIFooであることのみを知っているため、リファレンスiFooによって指し示されるオブジェクトのコンパイル時タイプと呼ばれます。 GetIFooreturn barステートメントが実行されたときに、この型情報が失われたことに注意してください。

Foo foo = (Foo)iFoo; 

はさらにダウン、あなたは上記のBar、何の階層に好きな型にキャストすることができますし、Barを含めて成功すると、コンパイル時の型は、あなたがそれを入力し、キャスト何に基づいて行われます。しかし、やはり実行時の型は同じままです。すなわち、Bar

+0

答えをありがとう。これは物事をより明確にします。この方法で実行時にFooを作成する別の方法はありますか? – allencage

+0

@allencage 'GetIFoo'メソッドを' static IFoo GetIFoo(){var foo = new Foo {Name = "MyName"};}のように変更すると、 fooを返す。 } '実行時型とコンパイル時型の両方が' Foo'になります。 – Vikhram

関連する問題