2016-10-28 2 views
12

私は、次のものが含まC#のプログラムに問題がある:スタティックメソッドで生成されたインスタンスをダウンキャストするにはどうすればよいですか?

class Program 
{ 
    static void Main(string[] args) 
    { 
     Child childInstance = Child.ParseFromA(@"path/to/Afile") as Child; 
    } 
} 

class Parent{ 
    int property; 

    public static Parent ParseFromA(string filename) 
    { 
     Parent parent = new Parent(); 
     // parse file and set property here... 
     return parent; 
    } 
} 

class Child : Parent 
{ 
    public void SomeAdditionalFunction() { } 
} 

このコードを実行すると、childInstancenullになります。

私は明示的なキャストとの割り当ての下にしようとしたが、例外で終了:
Child childInstance = (Child)Child.ParseFromA(@"path/to/Afile");

私はParentChildインスタンスにファイルのいくつかのタイプを解析したいので、私はでインスタンスを生成し、デザインを維持したいです静的メソッド。

適切な方法を教えてくださいchildInstance

答えて

23

ダウンキャストできません。オブジェクトがParentとして作成されると、は常にとなります。Parentです。 new object()stringにダウンキャストしようとするようなものです:これはうまくいかず、この文字列はどの文字列で表現されるべきですか?

したがって、唯一の解決策は、に正しいオブジェクトを作成することです。私はあなたのケースで見唯一のオプションは、あなたの静的メソッドがジェネリックにすることです:

public static T ParseFromA<T>(string filename) where T : Parent, new() 
{ 
    T t = new T(); 
    // parse file and set property here... 
    return t; 
} 

は使用方法:

Child childInstance = Parent.ParseFromA<Child>(@"path/to/Afile"); 

ジェネリック制約T : ParentTParentのサブタイプであることを保証し、かつnew()はそのTを保証しますパラメータのないコンストラクタがあります。

+2

ありがとう!あなたのソリューションはまさに私がやりたかったものです! 私はそれを適用し、完全に働いた。 – Malboma99

+2

あなたの例についてちょっとしたこと: 'Animal'を' Cat'にダウンキャストしようとすると全く問題ありません。もし 'Cat'なら' Cat'を、そうでなければ 'null'を受け取ります。著者が何をするか)。ここで問題となるのは、 'Animal'を作成した場合、抽象的な動物を作成することです。それはちょうど種類がないモデルです。あなたが男について話すならば、あなたは「ジョン」を意味するわけではありません - あなたは抽象的な人を意味します。私はそれが意図だったとはかなり確信していますが、あなたの例からは少し不明であると思いました。 – Archeg

+1

@Archeg:もちろん、あなたは完全に正しいです。私は私の例を修正し、いくつかのフレームワーククラスを使うことに決めました。 – Heinzi

3

あなたは静的メソッドを使用して主張し、反射やジェネリックを使用したくない場合は、あなたもnewキーワードの使用を検討することができます

class Parent 
{ 
    public static Parent ParseFromA(string filename) 
    { 
     Parent parent = new Parent(); 
     parent.Parse(filename); 
     return parent; 
    } 

    protected virtual void Parse(string fileName) 
    { 
     ... 
    } 
} 

class Child : Parent 
{ 
    public new static Child ParseFromA(string filename) 
    { 
     Child child = new Child(); 
     child.Parse(filename); 
     return parent; 
    } 

    protected override void Parse(string fileName) 
    { 
     base.Parse(fileName); 
     SomeAdditionalFunction(); 
    } 
} 

個人的に私はちょうどインスタンスメソッドを使用します。

var child = new Child(...); 
child.Parse(...); 

コードの余分な行は、よりクリーンなコードIMHOに対して支払う小さな代金です。 staticのように、継承のキーワードがうまく再生されません。

public static class ParentEx 
{ 
    public static T ParseFile<T>(this T source, string fileName) : where T : Parent 
    { 
     source.Parse(fileName); 
     return source; 
    } 
} 

、その後

var child = new Child().ParseFile(fileName); 
+0

または、基本クラスで仮想を使用し、子クラスでオーバーライド – Mafii

+0

@Mafiiインスタンスメソッド、はい。しかし、静的メソッドをオーバーライドすることはできません。 –

2

をあなたの静的メソッドを作成するために、どのような種類を知っていない場合は、あなたを:あなたはすべての後にワンライナーをしたい場合にも、常に、拡張メソッドにインスタンスメソッドをラップすることができますそれを渡す必要があります。たとえば、ジェネリックを使用して:

namespace ConsoleApplication18 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 
     var childInstance = Parent.ParseAs<Child>(@"path/to/Afile"); 

     childInstance.SomeAdditionalFunction(); 
    } 
    } 

    class Parent 
    { 
    int property; 

    public static T ParseAs<T>(string filename) where T : Parent, new() 
    { 
     var parent = new T(); 

     // parse file and set property here... 
     parent.property = 42; 

     return parent; 
    } 
    } 

    class Child : Parent 
    { 
    public void SomeAdditionalFunction() { } 
    } 
} 
1

子クラスではなく、親クラスにのみキャストできます。コンパイラは、オブジェクトが正しく構築されていることを安全に想定できず、子オブジェクトとして安全にアクセスするために必要なすべてのプロパティを保持しています。

Heinziが述べたような一般的な方法を使用するか、親クラスと子クラス内でパラメータ化されたコンストラクタとインスタンス化された解析メソッドを使用します。

class Parent 
{ 
    public Parent() { } 
    public Parent(string fileName) 
    { 
     Parse(fileName); 
    } 

    private void Parse(string fileName) 
    { 
     // Do your parsing stuff here. 
    } 
} 

class Child : Parent 
{ 
    public Child() { } 
    public Child(string fileName) : base(fileName) 
    { 
     // Parsing is done already done within the constructor of Parent, which is called by base(fileName) 
     // All you need to do here is initialize the rest of your child object. 
    } 
} 
関連する問題