web-dev-qa-db-ja.com

C#の継承。基本クラスから派生したクラス

基本クラスがあります

public class A   
{
    public string s1;
    public string s2;
}

派生クラスもあります:

public class B : A
{
    public string s3;
}

私のプログラムがクラスAのインスタンスを作成したとしましょう。

A aClassInstance = new A();

いくつかのパラメータが設定されました:

aClassInstance.s1 = "string 1";
aClassInstance.s2 = "string 2";

この時点で、クラスBのインスタンスを作成したいと思います。しかし、クラスAのインスタンスの値をBにすでに持たせたいと思います。

これDID動作しません:

public B bClassInstance = new B():
bClassInstance = (B)aClassInstance;

どちらもDIDこれ:

クラスA内にクローンメソッドを作成しました。

public B cloneA() {    
    A a = new A();
    a = (A)this.MemberwiseClone()
    return(B)a;
}

VSコードは上記の両方を取ります-しかし、実行時エラーが発生します

助けてください

16
Sam

あなたが持っている基本的な問題は、タイプBのインスタンスを構築しなければならないということです(これにはタイプAのプロパティが含まれています)。 Aインスタンスを複製するアプローチは機能しません。これは、タイプAのインスタンスが得られ、Bに変換できないためです。

タイプAのパラメーターを受け取るクラスAおよびBのコンストラクターを作成します。クラスBのコンストラクターは、値を基本クラスAに渡すだけです。クラスAのコンストラクターは、フィールドを自分自身にコピーする方法を知っています。

class A {
    public A(A copyMe) {
        s1 = copyMe.s1;
        ...
    }

class B : A {

    public B(A aInstance) : base(aInstance) {
    }

}

このように使用します。

A a = new A();
a.s1 = "...";

B b = new B(a);

[〜#〜]編集[〜#〜]

新しいフィールドや小道具を追加するときにAのコンストラクターを変更する必要がない場合は、リフレクションを使用してプロパティをコピーできます。カスタム属性を使用してコピーするものを装飾するか、Aのすべての小道具/フィールドのみをコピーします。

public A (A copyMe) {
    Type t = copyMe.GetType();
    foreach (FieldInfo fieldInf in t.GetFields())
    {
        fieldInf.SetValue(this, fieldInf.GetValue(copyMe));
    }
    foreach (PropertyInfo propInf in t.GetProperties())
    {
        propInf.SetValue(this, propInf.GetValue(copyMe));
    }
}

私はコードを試したことがありませんが、要点は明らかになるはずです。

28
Jan

クラスAで汎用クローンメソッドを作成できます。

     public T Clone<T>() where T : A, new() {
          return new T() { a = this.a, b = this.b};
     }

または、クローンを拡張可能にしたい場合:

     public T Clone<T>() where T : A, new() {
          var result = new T();
          this.CopyTo(result);
          return result;
     }

     protected virtual void CopyTo(A other) {
          other.a = this.a;
          other.b = this.b;
     }

あなたはそれをこのように使います:

     A  a = new A();
     // do stuff with a
     // Create a B based on A:
     B b = a.Clone<B>();

注意:この例では、新しいA()とMemberwiseCloneの両方がタイプAの新しいオブジェクトを作成します。

自分でcopyメソッドをコーディングしたくない場合は、 AutoMapper のようなツールを見ることができます。

9
GvS

遊んで、私が見ることができるすべてを読んだ後、GvSとJanによる上記のソリューションの両方が機能します。しかし、私が達成したかった最終結果は、Copyメソッドで各メンバーを強制的に書き出すことではありません。

理由:a)クラスが編集され、別のオブジェクトが追加された場合、copyメソッドを更新する必要があります。他の誰かがクラスを更新すると、これを忘れる可能性があります。

b)メンバーが多く、割り当てに時間がかかる場合があります。

c)それはただ正しく「感じ」ません。 (おそらく私はとても怠け者だからです)。

幸いなことに、同じ考えを持っているのは私だけではありません。 ValueInjectorを介して非常に簡単な解決策を見つけました。 (これらのボードで多く議論されています)。

Dllを取得した後(http://valueinjecter.codeplex.com/documentation)

コードは次のようになります。

A a = new A();
a.s1 = "...";


B b = new B();
b.InjectFrom(a);

それでおしまい :)

明らかに、以下を含める必要があります。

using Omu.ValueInjecter;

そして、それを参照に追加することを忘れないでください。

2
Sam

たとえば、JSONシリアライザーを使用することもできます。子クラスに静的メソッドを追加すると、次のように呼び出すことができます。

var porsche = Porsche.FromCar(basicCar);

ここで、「ポルシェ」は子クラス、「車」は基本クラスです。この場合、関数は次のようになります。

public class Porsche : Car
{
    public static Porsche FromCar(Car basicCar)
    {
        // Create a JSON string that represents the base class and its current values.
        var serializedCar = JsonConvert.SerializeObject(basicCar);

        // Deserialize that base class string into the child class.
        return JsonConvert.DeserializeObject<Porsche>(serializedCar);
    }

    // Other properties and functions of the class...
}

ここでの秘訣は、子で使用できるがベースでは使用できないプロパティはデフォルト値で作成されるため、プロパティのタイプに応じて、通常はnullになることです。デシリアライズもプロパティの名前で行われるため、すべてのプロパティがコピーされます。

このコードはテストしていませんが、以前に1、2回テストしたので、機能するはずです。それが誰かを助けることを願っています。

0
Sven Möhring