1. ホーム
  2. c#

[解決済み] GetType()は嘘をつくのか?

2023-02-12 18:34:49

質問

数日前にSOで行われた以下の質問に基づいています。 GetType()とポリモーフィズム と読みます。 Eric Lippert の の回答を読んで、もし GetType() を仮想化しないようにすることで、本当にオブジェクトがその Type .

具体的には、Ericの回答には次のように書かれています。

フレームワークの設計者は、オブジェクトが単に同じ型上の他の3つのメソッドと一貫性を持たせるために、その型について嘘をつくことを許すような信じられないほど危険な機能を追加するつもりはないでしょう。

今問題なのは、オブジェクトが を行う がその型について嘘をつくことを、すぐにわかるようにできるでしょうか?私はここで深く間違っているかもしれませんし、もしそうであれば説明を求めますが、次のコードを考えてみてください。

public interface IFoo
{
    Type GetType();
}

そして、当該インタフェースの次の2つの実装です。

public class BadFoo : IFoo
{
    Type IFoo.GetType()
    {
        return typeof(int);
    }
}

public class NiceFoo : IFoo
{
}

次に、以下のような簡単なプログラムを実行すると

static void Main(string[] args)
{
    IFoo badFoo = new BadFoo();
    IFoo niceFoo = new NiceFoo();
    Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString());
    Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString());
    Console.ReadLine();
}

案の定 badFoo は誤った Type .

さて、Eric がこの動作を " と表現していることから、これが重大な意味を持つかどうかはわかりません。 非常に危険な機能 しかし、このパターンが信頼できる脅威となる可能性はあるのでしょうか?

どのように解決するのですか?

いい質問ですね。私の見るところ、GetType がオブジェクト上で仮想であった場合のみ、仲間の開発者を本当に誤解させることができます。

あなたがしたことは、このようにGetTypeをシャドーイングすることに似ています。

public class BadFoo
{
    public new Type GetType()
    {
        return typeof(int);
    }
}

このクラスで(そして メソッドのサンプルコードです。 を使えば、確かに

int n1 = 12;
BadFoo foo = new BadFoo();

Console.WriteLine("n1 and n2 are the same type: {0}",
                  Object.ReferenceEquals(n1.GetType(), foo.GetType())); 
// output: 
// n1 and n2 are the same type: True

というわけで、ヤバイ、嘘に成功しましたね? まあ、イエスでもありノーでもあるのですが...。これを悪用する場合、BadFooインスタンスをどこかのメソッドの引数として使用することになります。 object またはオブジェクトの階層のための共通の基本型を期待します。このようなものです。

public void CheckIfInt(object ob)
{
    if(ob.GetType() == typeof(int))
    {
        Console.WriteLine("got an int! Initiate destruction of Universe!");
    }
    else
    {
        Console.WriteLine("not an int");
    }
}

しかし CheckIfInt(foo) は "not an int" と出力します。

つまり、基本的には (あなたの例に戻ると)、誰かがあなたの IFoo インターフェイスに対して書かれたコードによってのみ利用可能で、このインターフェイスは "custom" を持つという事実について非常に明確です。 GetType() メソッドがあることを非常に明確に示しています。

GetType() がオブジェクト上で仮想的であった場合のみ、以下のようなメソッドで使用できる "lying"の型を作成することができます。 CheckIfInt のようなメソッドで使用され、他の誰かによって書かれたライブラリで大混乱を引き起こすことができる "lying"型を作ることができる唯一のものです。