🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
バックアップ

バックアップとは、保存データやプログラムの複製を異なる記録装置などへ保存することを言います。バックアップを取っておくことで、機器のトラブルでデータが損傷するなどの不測の事態にもデータを複製することが可能です。

参照

参照は、プログラミングにおいて変数や関数といったメモリ空間上での所在を指示するデータのことを指します。その中にはデータ自体は含まれず、他の場所にある情報を間接的に指示するプログラムです。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

コピー

元のオブジェクトを破壊することなく、オブジェクトの複製を生成することをコピーと呼びます。

Q&A

解決済

4回答

2019閲覧

インスタンスのバックアップを取得したい

comet7360

総合スコア9

バックアップ

バックアップとは、保存データやプログラムの複製を異なる記録装置などへ保存することを言います。バックアップを取っておくことで、機器のトラブルでデータが損傷するなどの不測の事態にもデータを複製することが可能です。

参照

参照は、プログラミングにおいて変数や関数といったメモリ空間上での所在を指示するデータのことを指します。その中にはデータ自体は含まれず、他の場所にある情報を間接的に指示するプログラムです。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

コピー

元のオブジェクトを破壊することなく、オブジェクトの複製を生成することをコピーと呼びます。

0グッド

0クリップ

投稿2021/03/25 07:55

編集2021/03/25 08:32

こんにちは。
上手くお伝えできるか不安ですが、ご相談させてください。

personインスタンスのバックアップ(bkPerson)を取得したいです。
personに何か例外があった場合に、personをbkPersonで復元したいためです。

ただし条件があり、例えbkPersonから復元したpersonであったとしても、
personのインスタンスは、復元前と同じインスタンスで在りたいのです。
理由は、personインスタンスは、他のインスタンスから参照されているので、
復元時にpersonインスタンスが変わってしまうと、他のインスタンスからの参照が出来なくなるからです。

また、Personクラスにはたくさんのメンバが存在していることを想定しているので、
クラス内の各メンバを1つ1つ代入、、という処理も、できれば避けたいと思っています。

もしかすると、「メモリのバックアップ」という言い方のほうが適切かもしれません。
上記方法についてご存じの方がいらっしゃいましたらご教授お願いいたしますm(_ _)m

以下、当方の環境です。
Windows 10 64bit
.NET Core 3.0
VisualStudio 2019 v16.9.2

C#

1 class Program{ 2 static void Main(string[] args){ 3 Person person = new Person(); 4 5 Person bkPerson = person; // インスタンスのバックアップを取りたい。 6 7 try{ 8 person.Name = "hogehoge"; 9 }catch{ 10 person = bkPerson; // バックアップから復元したい。 11 } 12 } 13 } 14 class Person 15 { 16    // ★この例ではNameプロパティのみですが、もっとたくさんの 17    // メンバがあることを想定しています。 18 public String Name { get; set; } = "Hoge"; 19 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2021/03/25 08:15

> personのインスタンスは、復元前と同じインスタンスで在りたいのです。 > 理由は、personインスタンスは、他のインスタンスから参照されているので、 > 復元時にpersonインスタンスが変わってしまうと、他のインスタンスからの参照が出来なくなるからです。 この指すところの意味ですが、同じインスタンスとは、同じ参照の値を意味していますか? インスタンスのプロパティやフィールドの内容が同じ、ではなく。
comet7360

2021/03/25 08:18

ありがとうございます。はい、同じ参照の値を意味しています。 プロパティやフィールドの値が同じで在ったとしても、参照の値が違っていてはダメとしたいです。 (参照の値が変わると、他のインスタンスからの参照情報が途切れてしまうためです)
dodox86

2021/03/25 08:30

私は回答する術を持ちませんが、バックアップしたいクラスのインスタンスのプロパティやフィールドも別のあるクラスのインスタンスへの参照だと、かなり厳しくなりませんか。
sinya0320

2021/03/25 08:30

メモリの直参照でもしてるんですかね。 私ではカバーしきれない範囲っぽいので、離脱します。すみません。 他の方のために、C#のバージョン、.netFrameworkなのか、.netCoreなのか、またそれのバージョン を追記する事をお勧めします。 Visual Studioのバージョンもあった方が良いかも
comet7360

2021/03/25 08:35

>dodox86さん そのとおりで、Personクラス内のメンバも、別のあるクラスのインスタンスを参照しているかたちです。 やはり厳しいですかね。。 >sinya0320 はい、色んなインスタンス間で参照を持ち合っているかたちです。 ありがとうございます。開発環境を質問に記載しました。
guest

回答4

0

IEditableObject インターフェイス (System.ComponentModel) | Microsoft Docs

ここのサンプルが参考になるのではないかと思います。

投稿2021/03/25 09:24

Zuishin

総合スコア28669

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

comet7360

2021/03/25 13:55

おぉ、このようなIFがあるのですね、参考になります。 今後はこのような事態になる前に、このIFを実装するような設計にしたいと思います。 後学のために覚えておきます。ありがとうございます。
Zuishin

2021/03/25 14:08

なる前にっていうか、今からでも実装できますし、可読性のためにも拡張性のためにも実装すべきケースでしょうね。
comet7360

2021/03/25 14:16

ありがとうございます。 いま、実際にはこのPersonクラスに該当するクラスが50個程度あり、 各クラス内のメンバも20個程度あるのでなかなか大変なのですが、 出来るところから実装していこうと思います。 仰る通り、今後の開発でこれらのクラスを拡張していく予定があります。
Zuishin

2021/03/25 14:19

クラスが多いならなおさら。
guest

0

単純に復元用のメソッドを追加すればいいんじゃないですか?

C#

1 person.Import(bkPerson);

みたいな。
メソッド内で必要なプロパティをコピーすれば良いかと。

投稿2021/03/25 08:26

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

comet7360

2021/03/25 08:31

ありがとうございます。その方法でも可能ですね! ですが後出し情報で申し訳ないのですが、Personクラスにはたくさんのメンバが在ることを 想定しているので、クラス内のメンバ1つ1つを代入、、という処理はできるだけ避けたいのです。。
退会済みユーザー

退会済みユーザー

2021/03/25 08:38

面倒ならType.GetPropertiesでプロパティ列挙してコピーするなりすればよいかと思います。 (リフレクション経由するので速度は落ちますが) もしくは、単純なコピーにしたいならstruct にするって手もありますけど。
comet7360

2021/03/25 08:40

>radianさん ありがとうございます。 Personクラス内のメンバも、インスタンスの情報(参照の値)を変えずにコピーしたいのですが、 その場合はその各クラスでType.GetPropertiesを使用するかたちになりますか?
退会済みユーザー

退会済みユーザー

2021/03/25 08:46 編集

親からずっと辿ってGetPropertiesしていってもいいですけど、そこはやり方をよく考えた方がいいですね。
comet7360

2021/03/25 08:49

ありがとうございます。もう少し考えてみます。 最初は「インスタンスのメモリ情報をマルっとコピーして復元時にはその情報で上書き」 みたいなことを考えていたのですが、うまくいかないですね。。
退会済みユーザー

退会済みユーザー

2021/03/25 09:08

不都合が無ければ、classではなくstructにしてしまうのも手だと思いますけどね。 参照型ではないので、コピーも簡単です。
comet7360

2021/03/25 14:12

ありがとうございます。 情報が小出しになってしまい申し訳ないのですが、今回は、参照型でデータを持ちたいのです。 インスタンスを各クラスのメンバで共有することで、片方のクラスでそのメンバに変更を加えた際に、 もう片方のクラスにも変更内容を反映させるようにしたいので。 (それこそコピーメソッドでもよいのかもしれませんが。。)
guest

0

ベストアンサー

Personの中身を復元するのに必要な情報を格納する何らかの型を作り…

C#

1class BkupData 2{ 3 //必要なもの 4}

Personに,この情報を作る手段と,この情報から内容を復元する手段とを設ける

C#

1class Person 2{ 3 public BkupData CreateBackupData(){ ... } 4 public void RecoverFromBackupData( BackupData Bkup ){ ... } 5}

Personのメソッドを呼ぶ側が,あらかじめPersonのバックアップを取ってからメソッドを呼ぶ
→Personのメソッドが例外を投げてきたらバックアップを用いてPersonの中身を復元する

という話よりも,Person側の仕様を

Personのメソッドが例外を投げる際には,Personの中身はメソッドを呼ぶ前の状態に復元されている

という仕様にした方が,復元処理はいくらか楽になるように思います.
後者側だと,各メソッドは例外を投げる時点で「何をすれば "復元" になるか」を知っているであろうから,「全て」をバックアップしなくても済むハズなので.

投稿2021/03/25 08:08

編集2021/03/25 10:37
fana

総合スコア11985

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

comet7360

2021/03/25 08:25

ありがとうございます。なるほどです。これで出来そうですね。 ただ欲張ってしまい申し訳ないのですが、PersonクラスはNameプロパティだけでなく、 もっとたくさんのメンバを持つことを想定しています。(質問を修正いたします) 復元に必要なデータがたくさんあると、BkupDataクラスと、2つのメソッドの製造コストが 大きくなりますので、他の方法が無いか確認したいと思っています。
退会済みユーザー

退会済みユーザー

2021/03/25 08:38 編集

(別の回答に間違ってコメントしてしまったので削除)
fana

2021/03/25 08:54

実装コストを下げる方法があるのかは私にはわからないです. Personが他の型の参照を保持するとして, その「他の型」の立場から見れば,自身がPersonに保有されるかどうかは知らないでしょうから,その「他の型」にもバックアップと復元の機能を持たせねばならないとしたら,「うーん…」という感じです. さらにその「他の型」がまた別の… と,続いていくのでしょうし.
comet7360

2021/03/25 09:00

>fanaさん ありがとうございます。 >>その「他の型」の立場から見れば,自身がPersonに保有されるかどうかは知らないでしょうから その「他の型」も、Personに保有されていることを知っている場合があります。。 Personクラスのプロパティでpersonインスタンスを参照している場合があります。 クラス設計に問題があることは重々承知のうえですが、何とか実現方法を模索したいと思っています。。
fana

2021/03/25 09:12 編集

例外を投げる処理の側を, 「例外を投げるかもしれない処理が終わるよりも前には,復元が面倒な変更を行わない」 ような形にして,復元対象をある程度絞るみたいなことはできないのでしょうか? 何から何まで丸ごとバックアップして復元することを目指すのではなく. ある処理を構成するより細かい処理の単位で見ていけばその細かい処理で変更される範囲はずっと狭いだろうから,各所にちまちまと細かい単位の復元処理を仕込むような形になるのかな.
comet7360

2021/03/25 14:09

ありがとうございます。ベストアンサーにさせていただきました。 (radianさんと迷いましたが、ご回答いただいた時刻と、ご提案いただいた仕様 で実装することにしましたので) 「メモリのバックアップ→リストア」という処理は不可能なようなので、皆さんのご指摘通り、 クラス内の各メンバをそれぞれ代入(参照型の場合は更に潜って代入)することで復元することに決めました。 その方法を考えると、fanaさんのおっしゃる通り、 「事前にバックアップ→例外が起きれば全データを復元」よりも、 「例外が発生→影響のあるデータのみ復元」の方がいくらか楽になることを理解いたしました。 ご回答いただき、大変ありがとうございました!
guest

0

Personに新しいインスタンスを作るメソッドを追加してあげてください。

バックアップは代入ではなく、そのメソッドで
Person bkPerson = person.Clone();

class Person { public String Name { get; set; } = "Hoge"; // これを追加 public Person Clone() { return new Person() { Name = this.Name }; } }

※慣例的にClone()ですが、別に何でも良いです。

投稿2021/03/25 08:08

sinya0320

総合スコア211

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

comet7360

2021/03/25 08:14

ご回答ありがとうございます。 その場合ですと、bkPersonで復元したpersonは、 復元前のpersonとインスタンスが変わってしまうと思います。 今回は、何とかpersonのインスタンスを変えずに復元したいのです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問