質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

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

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

Q&A

解決済

4回答

2122閲覧

C# プロパティをまとめてコードの可読性を高めたい

naritamago

総合スコア15

C#

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

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

0グッド

0クリップ

投稿2018/08/31 07:36

編集2018/09/01 03:43

Xamarin勉強中です。

動的に変化する値をデータバインディングでViewに表示させるViewModelを実装していますが、
プロパティが多く、以下のような状況になっています。

ViewModel

1 private string _xAccel; 2 public string xAccel 3 { 4 get { return _xAccel; } 5 set 6 { 7 _xAccel = value; 8 OnPropertyChanged("xAccel"); 9 } 10 } 11 private string _yAccel; 12 public string yAccel 13 { 14 get { return _yAccel; } 15 set 16 { 17 _yAccel = value; 18 OnPropertyChanged("yAccel"); 19 } 20 } 21 private string _zAccel; 22 public string zAccel 23 { 24 get { return _zAccel; } 25 set 26 { 27 _zAccel = value; 28 OnPropertyChanged("zAccel"); 29 } 30 } 31 private string _xHoge; 32 public string xHoge 33 { 34 get { return _xHoge; } 35 set 36 { 37 _xHoge = value; 38 OnPropertyChanged("xHoge"); 39 } 40 } 41/////////////////////中略///////////////////// 42

ViewModelはINotifyPropertyChangedの実装を提供する基本クラスを継承しています。
Accelは加速度センサーの事なんですが、これがジャイロ・コンパス・GPS・etc…と増えて行くとプロパティだけでコードが肥大化してしまうのでセンサー単位で纏めたいのですが、どうすれば良いのでしょうか?

###BA選択後追記
今回質問させていただいて、いろいろな実装方法を教えていただきました。MVVMのポリシーの話も議論されておりましたが、一先ずはFodyを使用した方法でVMに記述し、#regionでまとめるといった方法を採択しました。
質問してよかったです。ありがとうございました。

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

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

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

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

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

guest

回答4

0

質問は「プロパティをまとめたい」ですが、その後のコメントを見るとプロパティの記述が簡単になりさえすればいいように見えます。
また、プロパティは何か特別な処理をするものではなく、定型的なものが並ぶだけなのでそれをループで処理できれば最も意図に沿うのではないかと思いました。

テキストテンプレートを使うと、いくらプロパティが増えても大丈夫です。
ただし、補完が使えなくなるので、主となるソースとは別ファイルにして partial class とすれば良いと思います。これによって一つのクラスを複数のファイルに分割して記述できます。

C#

1<#@ template debug="false" hostspecific="false" language="C#" #> 2<#@ assembly name="System.Core" #> 3<#@ import namespace="System.Linq" #> 4<#@ import namespace="System.Text" #> 5<#@ import namespace="System.Collections.Generic" #> 6<#@ output extension=".cs" #> 7 8using System; 9using System.Collections.Generic; 10using System.Linq; 11using System.Text; 12using System.Threading.Tasks; 13 14namespace ConsoleApp1 15{ 16 public partial class Class1 17 { 18<# 19var names = new string[] 20{ 21 "xAccel", "yAccel", "zAccel", "xHoge" 22}; 23foreach (var name in names) 24{ 25#> 26 private string _<#= name #>; 27 public string <#= name #> 28 { 29 get => _<#= name #>; 30 set 31 { 32 if (value == _<#= name #>) return; 33 _<#= name #> = value; 34 OnPropertyChanged("<#= name#>"); 35 } 36 } 37<# 38} 39#> 40 } 41} 42

テキストテンプレートの記述は上記です。
プロパティが増えた時には names の要素を増やしてください。
これを保存すると次のように展開された cs が自動的に生成されます。

C#

1 2using System; 3using System.Collections.Generic; 4using System.Linq; 5using System.Text; 6using System.Threading.Tasks; 7 8namespace ConsoleApp1 9{ 10 public partial class Class1 11 { 12 private string _xAccel; 13 public string xAccel 14 { 15 get => _xAccel; 16 set 17 { 18 if (value == _xAccel) return; 19 _xAccel = value; 20 OnPropertyChanged("xAccel"); 21 } 22 } 23 private string _yAccel; 24 public string yAccel 25 { 26 get => _yAccel; 27 set 28 { 29 if (value == _yAccel) return; 30 _yAccel = value; 31 OnPropertyChanged("yAccel"); 32 } 33 } 34 private string _zAccel; 35 public string zAccel 36 { 37 get => _zAccel; 38 set 39 { 40 if (value == _zAccel) return; 41 _zAccel = value; 42 OnPropertyChanged("zAccel"); 43 } 44 } 45 private string _xHoge; 46 public string xHoge 47 { 48 get => _xHoge; 49 set 50 { 51 if (value == _xHoge) return; 52 _xHoge = value; 53 OnPropertyChanged("xHoge"); 54 } 55 } 56 } 57}

###追記
プロパティ名だけでなく型も指定する場合

C#

1<#@ template debug="false" hostspecific="false" language="C#" #> 2<#@ assembly name="System.Core" #> 3<#@ import namespace="System.Linq" #> 4<#@ import namespace="System.Text" #> 5<#@ import namespace="System.Collections.Generic" #> 6<#@ output extension=".cs" #> 7 8using System; 9using System.Collections.Generic; 10using System.Linq; 11using System.Text; 12using System.Threading.Tasks; 13 14namespace ConsoleApp1 15{ 16 public partial class Class1 17 { 18<# 19var properties = new[] 20{ 21 new { Name = "xAccell", Type = "string" }, 22 new { Name = "yAccell", Type = "string" }, 23 new { Name = "zAccell", Type = "string" }, 24 new { Name = "xHoge", Type = "string" }, 25}; 26foreach (var property in properties) 27{ 28#> 29 private <#= property.Type #> _<#= property.Name #>; 30 public <#= property.Type #> <#= property.Name #> 31 { 32 get => _<#= property.Name #>; 33 set 34 { 35 if (value == _<#= property.Name #>) return; 36 _<#= property.Name #> = value; 37 OnPropertyChanged("<#= property.Name #>"); 38 } 39 } 40<# 41} 42#> 43 } 44}

投稿2018/09/01 02:26

編集2018/09/01 03:36
Zuishin

総合スコア28660

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

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

0

ベストアンサー

いくつか対策はありますが、実装方法が簡素になるのは次のいずれかでしょう。

前者はReactiveプログラミングをしないのであれば、不要ライブラリが多数導入されますし、オーバースペックになるかもしれません。
後者はILの修正が入る為、黒魔術感がありますが、古くからあって利用者も多いライブラリなので、そこまで忌避するものでもない気がします。

こちらの記事に良くまとまって見るので一読いただいて、いずれを選択するか判断していただくのが良いと思います。

投稿2018/08/31 08:52

nuits.jp

総合スコア346

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

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

naritamago

2018/08/31 09:58 編集

nuitsさん、ご回答ありがとうございます。Fody、早速試そうとしてみたのですが「FodyWeavers.xmlが見付からない」とエラーが出たので中断しました。またnuitsさんのブログにもたどり着いたのですが、VisualStudio2017では使えない?というような記述があったのですが… 一応当方の環境はVisualStudioforMacです。 あと、今の所Reactiveは使う予定はありません。
nuits.jp

2018/08/31 13:18 編集

動かないのは、MethodDecorator.Fodyです。PropertyChanged.Fodyは動いていました。ここ数ヶ月触ってませんが。 Fody系のものを使う場合、プロジェクトルートにFodyWeavers.xmlを追加してあげる必要があります。 中身はこんな感じ <?xml version="1.0" encoding="utf-8" ?> <Weavers> <PropertyChanged/> </Weavers> VS4Macでは直接試したことがそう言えば無いので、後で試してまたここに返信しますね。 遅い時間になると思いますが。
naritamago

2018/08/31 14:02

ろくに調べもしないで適当なことを言ってしまい、失礼しました。 訳あってVS4MacではなくVS2017なのですが、Fody動かすことができました。 ``` public string xAccel { get; set; } public string yAccel { get; set; } public string zAccel { get; set; } ``` これだけで動くのマジで黒魔術ですね… 正直めちゃくちゃベストアンサーにしたいんですが、チーム開発のときに説明がめんどくさくなるのと、hihijijiさんのやり方も試してみたいと思いますのでクローズまで少しお待ちください。
guest

0

例えば、
AccelerationSensorsServiceとでも名前を付けたModelのクラスを作って
そのクラスなかで変更通知付きのX,Y,Zのプロパティを公開して
ViewModelではそのインスタンスを公開すればOKでは?

投稿2018/08/31 09:39

hihijiji

総合スコア4150

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

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

nuits.jp

2018/08/31 14:21

この方法は、二つほど問題があると思います。 1. 変更通知はModelからイベントが発生するが、Viewが監視しているのはVMのイベントなので、実際にはおそらくプロパティが更新されても画面が更新されない 2. ModelのプロパティをVMのプロパティとしてそのまま公開するのは、ModelがVMによってカプセル化されておらず、設計的にあまり良いとは言えない そもそもModelにはVMに書くのが大変だと質問者がおっしゃっていたコードと同じコードを書かないといけないので、この場合は適さないかもしれませんね。
hihijiji

2018/09/01 01:11

MVVMの概念を語ると宗教論になってしまいますので概念論は避けます 1.普通に更新されます。 2.具体的にどんな弊害がありますか?
Zuishin

2018/09/01 01:14

カプセル化などする必要ありません。View は Model に依存して大丈夫です。 VM のプロパティのプロパティをバインドすればいいので 1 についても問題ありません。
nuits.jp

2018/09/02 14:28

hihijijiさん MVVMに触れない範囲で回答させていただきます。 まず、AccelerationSensorsServiceのプロパティをVMのプロパティとして公開する、という意味と取り違えていました。失礼しました。 であれば更新されますね。 ただその方法はAccelerationSensorsServiceに、INotifyPropertyChanged絡みのコードが移動しているだけではありませんか? ViewModelがシンプルになった代わりにModelが煩雑になって、問題個所が異動しただけで解決に至っていないと思いますが如何でしょうか?
hihijiji

2018/09/03 02:13

表題「プロパティをまとめてコードの可読性を高めたい」 および「センサー単位で纏めたい」に対して ・ViewModelをシンプルにして可読性を高める。 ・Modelの構造化を進めて保守性を上げる。 の2点を意図した回答です。 コード量を減らす意図は全くありません。
hihijiji

2018/09/03 04:14

それとViewModelの実装如何に関わらず、Modelが不変でない限りModelにINotifyPropertyChangedの実装は必須です。
nuits.jp

2018/09/03 07:04

AndroidもiOSも加速度はイベントリスナーで受け取るので、Modelではイベントとして処理するイメージでいました。 確かにイベントで扱われないならおっしゃる通りですね。
guest

0

1 #region を使う
https://msdn.microsoft.com/ja-jp/library/windows/apps/9a1ybwek(v=vs.120)

2 MVVM用のライブラリは、便利機能があるので使う。
https://qiita.com/kiichi54321/items/89f5a6d265710b51aa0d 
コードスニペットを組み合わせるといい。

public string property{get{return _property ;}set{Set(ref _property ,value);}} private string _property = default(string);

これくらいの記述量で済む

3 センサー周りで固めたいのなら、それ用のVMをつくる。
別に、VMの中にVMを置いたっていい。

public class メインVM { public センサーVM センサーVM{get;set;} = new センサーVM(); }

サービスクラスを作って、DIするのがクールかな。

4 プロパティをクラスにする。

public class プロパティ<T>: INotifyPropertyChanged { private T _value = defult(T); public T Value { 定番のINotifyPropertyChangedの処理 } }

使い方

public class メインVM { public プロパティ<int> プロパティ名{get;} = new プロパティ<int>(); }

まぁ、ゼロ機能なリアクティブプロパティと同じなんですけど。

投稿2018/08/31 14:17

編集2018/08/31 14:45
kiichi54321

総合スコア1984

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問