54157

[code]

    public class A
    {
        public string Value1 { get; set; }
        public string Value2 { get; set; }
        ・・・
        public string Value100 { get; set; }
    }
    
    public class B : A
    {
        public B(A a)
        {
            this.Value1 = a.Value1;
            this.Value2 = a.Value2;
            ・・・
            this.Value100 = a.Value100;
        }
    }
    
[/code]

基底クラスが保持している値を派生クラスのインスタンスにコピーする簡潔な記述方法はあるでしょうか。  
上記のコードのように基底クラスに多くのプロパティ（またはフィールド）がある場合、単純にコピーロジックを書くと長くなってしまうので、もっと簡潔に書ける方法はないかと思い、質問しました。


CC BY-SA 4.0
2019-04-13T14:12:45.240
54142
2019-04-15T04:14:33.523
3925
question
c#
派生クラスに基底クラスの値をコピーするには


> 上記のコードのように基底クラスに多くのプロパティ（またはフィールド）がある場合

残念ながら設計が悪いとしか言いようがありません。類似の目的を持つプロパティが多数並ぶのであれば、それらは配列やDictionary、その他適切なデータ構造で表現されるべきです。

> 単純にコピーロジックを書くと長くなってしまう

設計が悪い以上、設計を見直すか冗長なコードを容認するほかないでしょう。

* * *

そもそもBはAを継承する意義があるのかも疑問です。（そして継承しているのになぜコピーする？） もしかして包含の方が適切では？


CC BY-SA 4.0
2019-04-13T21:54:22.610
54149
2019-04-13T21:54:22.610
4236
54142
answer


条件さえ合えば以下のような方法もあります。

# シリアライズして復元

Aがシリアライズ可能であれば、シリアライズ化して復元する方法が使えます。

[code]

    void Test()
    {
        A a = new A();
        B b = B.Create(a);
    }
    
    [DataContract]
    public class A
    {
        [DataMember]
        public string Value1 { get; set; } = "A1";
        [DataMember]
        public string Value2 { get; set; } = "A2";
    }
    
    [DataContract]
    public class B : A
    {
        [DataMember]
        public string ValueB1 { get; set; } = "B1";
    
        public static B Create(A a)
        {
            using (var ms = new MemoryStream())
            {
                var serializerA = new DataContractSerializer(typeof(A));
                serializerA.WriteObject(ms, a);
                ms.Seek(0, SeekOrigin.Begin);
                var serializerB = new DataContractSerializer(typeof(B));
                var classB = (B)serializerB.ReadObject(ms);
                // classB.ValueB1 = "B1"; // TODO: デシリアライズではコンストラクタが実行されないので適時初期化
                return classB;
            }
        }
    }
    
    
[/code]

# クラスAのメソッドを拡張

メソッドを追加するだけであれば、クラスBの必要はなく、拡張メソッドで対応可能です。

[code]

    void Test()
    {
        A a = new A();
        a.Dump();
    }
    
    public static class ClassAExtensions
    {
        public static void Dump(this A self)
        {
            Debug.WriteLine(self.Value1 + self.Value2);
        }
    }
    
[/code]


CC BY-SA 4.0
2019-04-14T06:39:16.327
54157
2019-04-14T06:39:16.327
14817
54142
answer


継承している以上は `B` の部分オブジェクトとして `A`
が存在するわけで、「継承しているのにコピーするのはなぜ？」というのはオイラも当然そう疑問に思います。

[code]

    class ATest
    {
        int a;
        public int A
        {
            get { return a; }
            set { a = value; }
        }
    }
    class BTest : ATest
    {
        int a;
        public int new A
        {
            get { return a; }
            set { a = value; }
        }
    }
    static void Main()
    {
        ATest t = new ATest();
        t.A = 1;
        BTest u = new BTest();
        u.A = t.A;
        ++u.A;
        Console.WriteLine(t.A);
        Console.WriteLine(u.A);
        ATest x = u;
        Console.WriteLine(x.A); // 何が表示されるか実行前に検討
    }
    
[/code]

`B` で改めて `A` の機能を実装すると変数や関数が２重に存在してしまうので「継承する」のメリットを全く一切生かせていません。 DRY
原則にも反していて、オイラなら元の要求を蹴っちゃうでしょう。

`B` の部分オブジェクトとして派生元と「別の」 `A` が必要なのであれば、それは派生でなくて包含であるべきであろう、は既に回答されてますよね。

元の要求がおかしいときそれを拒絶できないとしたら、開発体制に何か問題があるのかもしれません。それでもあえて再実装する必然があるのであれば、既についている別回答で。

* * *

コメントを受けて追記

要求が

`A a = new A();` なるオブジェクト `a` が既にあって  
`B b = new B(a);` のように別オブジェクト `b` を生成する

のであれば `A` の複写ルーチンは必須です ([c++](/questions/tagged/c%2b%2b "'c++' のタグが付いた質問を表示")
でいうところのコピーコンストラクタ。 [c#](/questions/tagged/c%23 "'c#' のタグが付いた質問を表示")
にコピーコンストラクタはない)

だって別オブジェクト（別インスタンス）なんだからコピーしなきゃ「別」にならないもん。その手段としてちまちま手書きするか、シリアライズするかはお好きな方法で。

[c#](/questions/tagged/c%23 "'c#' のタグが付いた質問を表示") 的発想はやはり

[code]

    class B
    {
        A a;
    }
    
[/code]

のように、コピーせず参照を持つだけに留める、でしょうか。この場合「派生」させるわけにはいかないので設計変更っす。

こんなのも考えてみたけどオイラ個人がこれを実用するかと問われると No.

[code]

    class A
    {
        public A_detail detail;
        public A() { ... }
        public A(A that) { this.detail = that.detail; }
        /* A のメンバは detail を使って実装 */
    }
    class B : A
    {
        public B(A that) { this.detail = that.detail; }
        /* ... 追加メンバー ... */
    }
    
[/code]

とかなんとか。この場合 `detail` が「複写されていない」ことに注意（派生元と派生先で１つの `detail` を共有している）


CC BY-SA 4.0
2019-04-15T02:41:48.280
54165
2019-04-15T04:14:33.523
2019-04-15T04:14:33.523
8589
8589
54142
answer