前提
- ASP.NET MVC 5 (C#) を使用したシステムを開発しています。
- モデルの実装についての質問です。
実現したいこと・試したこと
- 1 つのフィールドに対し、複数の値を持たせたい(?)です。
↓ 現行
csharp
1// 一行分のデータのモデル 2public class HogeRow 3{ 4 public string FugaName { get; set; } // ★現行はただの string 型プロパティ 5} 6... 7 8var model = new HogeRow(); 9model.FugaName = "ふがふが";
↓ こんな感じで持ちたい
csharp
1// 一行分のデータのモデル 2public class HogeRow 3{ 4 public MyField FugaName { get; set; } // ★自作クラス型のプロパティにする 5} 6... 7 8var model = new HogeRow(); 9model.FugaName.Value = "ふがふが"; // プロパティ値。 10model.FugaName.Org = "フガフガ"; // [参照用として持ちたい] 下位権限者が入力した値が入る 11model.FugaName.Mod = "FUGA"; // [参照用として持ちたい] 上位権限者側で修正した値が入る 12 13... 14public class MyField 15{ 16 public string Value { get; set; } 17 public string Org { get; set; } 18 public string Mod { get; set; } 19 ... 20 // ToString() をオーバーライド 21 public override string ToString() 22 { 23 return this.Value; 24 } 25 // MyField → string への変換演算子を定義する (implicit = 暗黙の変換) 26 public static implicit operator string(MyField val) 27 { 28 if (val == null) return null; 29 return val.Value; 30 } 31}
- 『 基本的に 通常の string 型プロパティと同じように扱いたいが、+α の値も持ちたい 』
というのが最終的な希望です。
問題点1:キャスト
最初は string 型を継承した自作クラスを作りたい・・・ と思ったのですが、シール型は継承できないと怒られたので前出のようにしてみました。
public static implicit operator string(MyField val)
を実装したので、以下のキャストは通ります。
csharp
1var str = (string)model.FugaName; // OK
しかし、as でのキャストがエラーになります。
csharp
1var str = model.FugaName as string; // 'MyFieldValue': シール型 'string' から派生することはできません。
【質問1】
上記が通るようにする方法はないでしょうか・・・?
(別の掲示板 stackoverflow を見てみたら "ないよ!" という書き込みがあったのですが・・・ どうしてもありませんか・・・)
問題点2:検証属性
- 件のモデルでは、検証属性を色々使っています。
csharp
1// 一行分のデータのモデル 2public class HogeRow 3{ 4 [Required] 5 [StringLength(10, ErrorMessage = "10桁以下で入力してください")] 6 public MyField FugaName { get; set; } 7}
【質問2】
String 値を検証する 検証属性を使いたいのですが、
これも都度 「StringLengthAttribute を継承した MyStringLengthAttribute ...」 などを実装するしかないでしょうか?
(MyField.Value を検証して欲しいです)
public static implicit operator string(MyField val)
を実装したのでそのまま検証してくれないかな、とちょっと期待したのですがエラーが出ました。
('MyField': シール型 'string' から派生することはできません。)
使いたい検証属性を全部実装するしかないでしょうか。
追記:そもそもの修正要件
現状、単純に
「下位権限者が入力する」
「それを上位権限側で確認する(参照するのみ)」
というシステムがあります。
それに対し、
「上位権限者側でも修正を入れたい」
という要件が上がってきました。
なので、それぞれの入力フィールドに対し
「下位権限者による入力値」Org
「上位権限者による入力値」Mod
「最終的な採用値」Value
を持ちたいと思っています。
(Org, Mod は画面表示用として持ちたいだけ)
検討1:それぞれプロパティを個別に用意する
まず考えたのは以下ですが、プロパティが多く、同様のモデルも多い為、ひとまず無しとしました。
csharp
1// 一行分のデータのモデル 2public class HogeRow 3{ 4 public string FugaName { get; set; } 5 public string OrgFugaName { get; set; } 6 public string ModFugaName { get; set; } 7 /* 8 さらに 9 「Orgのデータがあるか」 10 「Modのデータがあるか」 11 「上位権限者による編集が行われているか」 12 などの判定ロジックも欲しい。MyField のように自作クラス化するならその中に作ってしまえるけど・・・ 13 */ 14 ... 15}
検討2:モデルの入れ子にする
次に以下のパターンも考えました。
csharp
1// 一行分のデータのモデル 2public class HogeRow 3{ 4 public HogeRow Org { get; } 5 public HogeRow Mod { get; } 6 7 public string FugaName { get; set; } 8 ... 9} 10/* 11 model.FugaName 12 model.Org.FugaName 13 model.Mod.FugaName 14 のようにアクセスする 15*/
このケースについては、以下が気になった為 なしとしました。
・HogeRow には更新系のメソッドなども定義しているが、Org や Mod ではそれらのメソッドを呼んで欲しくない。(呼ばなければ良いだけなのですが、呼んでほしくないメソッドが定義されているというのが気になりました)
⇒ なお、サンプルコードでは省いていますが、HogeRow は既に別の基底クラスを継承しています。
なので「プロパティだけを定義したクラスを別に作って、Org, Mod はそのクラスで定義、HogeRow はそのクラスを継承」という方法もちょっと難しいです。
・やはり プロパティ単位で Org や Mod を扱いたい。
(model.Org.FugaName ではなく model.FugaName.Org で扱いたい)
「上位権限者による編集が行われているか」の判定等をするのにもその方がやりやすいので・・・
検討3:ディクショナリで持つ
参照用の値はディクショナリに溜めようかとも考えたのですが、
文字列でアクセスするのがちょっと嫌だったので却下しました。
csharp
1// 一行分のデータのモデル 2public class HogeRow 3{ 4 public string FugaName { get; set; } 5 ... 6 7 // key=権限区分@プロパティ名で Org, Mod の値を持つ 8 private Dictionary<string, string> dict = new Dictionary<string, string>(); 9 public string GetFieldValue(string kengenKbn, string fieldName) 10 { 11 // 取得用メソッドなどを用意 12 } 13} 14/* 15 model.FugaName 16 model.GetFieldValue("1", "FugaName") 17 model.GetFieldValue("2", "FugaName") 18 のようにアクセスする 19*/
以上です。
もし分かる方がいらっしゃいましたら よろしくお願いします。
回答1件
あなたの回答
tips
プレビュー