LoginSignup
4
4

More than 3 years have passed since last update.

[C#] インデクサを使って、クラスのメンバ(プロパティ)をリストのように扱う

Last updated at Posted at 2020-09-08

データ型クラスのプロパティメンバを、リストのようにインデクサでアクセス出来るようにしたい。

題材

下記のUserInfoクラスのプロパティを、インデクサでアクセス出来るようにする。

UserInfo.cs
public class UserInfo
{
 public UserInfo(List<String> userList)
 {
  ID=userList[0];
    Name=userList[1];
    Password=userList[2];
    email=userList[3];
  }
  public string ID{get;set;}
  public string Name{get;set;}
  public string Password{get;set;}
  public string email{get;set;}
}

前準備 添字でアクセス

userInfo.cs
public class UserInfo
{      
  public UserInfo(List<String> userList)
  {
    var properties = typeof(UserInfo).GetProperties();
    {
      for (var i = 0; i < userList.Count; i++)
      {
        var name = properties[i].Name;
        //userListでプロパティをまとめて初期化
        this[name] = userList[i];
      }
    }          
  }
  public string ID{get;set;}
  public string Name{get;set;}
  public string Password{get;set;}
  public string email{get;set;}
 private string this[string propertyName]
  {
    get => typeof(UserInfo).GetProperty(propertyName).GetValue(this).ToString();
    set => typeof(UserInfo).GetProperty(propertyName).SetValue(this, value);
  }
}

解説

string this[string propertyName]

このプロパティを追加することで、添字によるアクセスが可能になる。

get
  • typeof(UserInfo).GetProperty(propertyName).GetValue(this).ToString()

↑GetValueの戻り値はobject型なので、string型に変換している。

set
  • typeof(クラス名).GetProperty(propertyName).SetValue(this,value)

コンストラクタ

  • typeof(UserInfo).GetProperties() クラスのプロパティを配列で取得。
  • properties[i].Name 各プロパティ名を取得出来るので、ループ処理が可能になる。

このままだとあまり意味が無いので、インデクサでアクセス出来るようにする。

本番1 インデクサでアクセス

下記をUserInfoクラスに追加

userInfo.cs
private List<string> NameList;
public string this[int num]
{
  get => this[NameList[num]];
  set => this[NameList[num]] = value;
}

NameListはプロパティ名一覧が入ったリスト(プロパティ名のインデックス用途)として使います。

string this[int num]

this[string propertyName]をラッパー。
NameList[num]でthis[string propertyName]の添字に変換します。

これにより、インデクサでのアクセスが出来るようになります。

ただ、これだけでは列挙型として使うことができません。

本番2 列挙可能にする

IEnumerableを継承し、IEnumerableインターフェイスを作成。

GetEnumeratorを実装することで、列挙型として扱えるようになります。

userInfo.cs
// UsefInfoの変更、追加部分のみ記述
public class UserInfo : IEnumerable<string>
{
  //GetEnumerator実装
 public IEnumerator<string> GetEnumerator()
 {
  for (var i = 0; i < NameList.Count; i++)
   {
    yield return this[i];
  }
 }
  //IEnumerable(非ジェネリック型)のGetEnumeratorも実装
 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
 {
   return this.GetEnumerator();
 }
}

全体像

UserInfo.cs
public class UserInfo : IEnumerable<string>
{      
  public UserInfo(List<String> userList)
  {
    var properties = typeof(UserInfo).GetProperties();
    NameList = new List<string>();
    //propertiesから、各Name取り出し
    foreach (var (name, index) in properties.Select((prop, index) => (prop.Name, index)))
    {
      if(index == properties.length - 1)
      {
        //配列の最後はthisプロパティなので、スキップする
        break;
      }
      //UserInfoのプロパティ名のリストを作成
      NameList.Add(name);
      //全プロパティを初期化
      this[name] = headerlist[index];
    }
  }
  public string ID{get;set;}
  public string Name{get;set;}
  public string Password{get;set;}
  public string email{get;set;}
  //プロパティのインデックス用途
  private List<string> NameList;

  //添字でのアクセス用
 private string this[string propertyName]
  {
    get => typeof(UserInfo).GetProperty(propertyName).GetValue(this).ToString();
    set => typeof(UserInfo).GetProperty(propertyName).SetValue(this, value);
  }
  //インデクサでのアクセス用
  public string this[int num]
  {
    get => this[NameList[num]];
    set => this[NameList[num]] = value;
  }
  //リスト型への代入用
  public List<string> ToList()
  {
    var res = new List<string>();
    NameList.ForEach(name => res.Add(this[name]));
    return res;
  }
  public IEnumerator<string> GetEnumerator()
 {
  for (var i = 0; i < NameList.Count; i++)
  {
   yield return this[i];
  }
 }  
 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
 {
   return this.GetEnumerator();
 }
}

結果

var User=new UserInfo(new List<string>{"012","user","pass","xx@xx.com"});
//添字でアクセス
User[0] = "dummy";
if(User.ID == "dummy")
{
    //一致
}
Console.WriteLine(User[3]);
//xx@xx.com

foreach(var val in User)
{
  Console.WriteLine(val);
  //012
  //user
  //pass
  //xx@xx.com
}
var list=User.ToList()
//list:{"012","user","pass","xx@xx.com"}

インデクサでのアクセス、foreachでのループが出来るようになりました。
出来ましたが、手順が多く冗長な気がします。
もっといいやり方があれば教えて頂けるとありがたいです。

参考

【C#】プロパティ名でプロパティにアクセスする

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4