20200908のC#に関する記事は5件です。

Prism コードサンプル学習:02-Regions

Prism コードサンプル学習:02-Regions

はじめに

以下の記事の続きです。
https://qiita.com/mngreen/items/49767e120292896d3937

02-Regions

本サンプルではRegionManagerクラスを用いて、領域に名称を与えるサンプルのようです。

<Window x:Class="Regions.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://prismlibrary.com/"
        Title="Shell" Height="350" Width="525">
    <Grid>
        <ContentControl prism:RegionManager.RegionName="ContentRegion" />
    </Grid>
</Window>
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
        }
    }

ポイントとしては以下でしょうか。

  • 前回はBootstrappprを利用していたが、そのBootstrapperを隠蔽するPrismApplicationクラスが利用されている
    • PrismApplicationの基底クラスはこちら
  • MainWindowでは、ContentControlコントロールに添付プロパティであるRegionManager.RegionNameプロパティに"ContentRegion"がセットされている
  • 名前が設定されると、その領域を指定して画面遷移させられることができる

おわりに

今回はRegionManagerクラスのソースコードを読み、領域に名前を付ける方法が分かりました。
所感ですが、領域にRegionManagerを経由させて名前を定義し、コンテンツを色々登録しておけば後からビューをどんどん追加することもできそうです。
次回、03-CustomRegionsについて見ていこうと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ASP.NET Core の IHttpClientFactory を使ったときに直接 HttpClient を DI したら何が渡されてくるのか

IHttpClientFactory のドキュメントを見ると IHttpClientFactory を受け取って CreateClient をするか、型指定されたクライアント機能を使って HttpClient を受け取るかという方法が書いてあるのですが、型指定されていない普通のクラスで HttpClient を DI してもらったらどうなるのか?というのが明示的に書いてないようなので調べてみました。(書いてあったらごめんなさい)

答えは以下のコードにありました。

https://github.com/dotnet/runtime/blob/254ef0f7f7f429ec238735fe6132805e3c38a19f/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs#L59

IServiceCollection に対して AddHttpClient をすると、内部で HttpClient も登録されていて IHttpClientFactory の CreateClient(string.Empty) をした結果のインスタンスがわたってくるみたいです。

HttpClientFactoryServiceCollectionExtensions.cs
// Register default client as HttpClient
services.TryAddTransient(s =>
{
    return s.GetRequiredService<IHttpClientFactory>().CreateClient(string.Empty);
});

なので IHttpClientFactory を受け取って CreateClient するだけなら直接 HttpClient を受け取るようにしてしまってもよさそうですね。

ふぅ、すっきり。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Azure Functions で設定情報を使いたい

Azure Functions で設定情報を IConfiguration 型で扱いたい。欲を言えば IOptions<T> で扱いたいというケースについて。

端的に言うとドキュメントに記載があります。以下のページにいくと Azure Functions での DI の仕方が書いてあって、その中には IConfiguration がプラットフォームから提供されているのでそれを使う感じです。

.NET Azure Functions で依存関係の挿入を使用する

やってみよう

Azure Functions のプロジェクトを作成したら Microsoft.Azure.Functions.Extensions を参照に追加します。そして、Startup.cs クラスを作ります。Startup クラスは Microsoft.Azure.Functions.Extensions.DependencyInjection.FunctionsStartup クラスを継承して Configure メソッドで色々追加していきます。

以下のクラスはプラットフォームで提供しているから使ってもいいよってドキュメントに書いてあります

  • Microsoft.Extensions.Configuration.IConfiguration
  • Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider

デバッガーで止めてみると色々 (96 個!?) 登録されてるみたいですけど、あんまり登録されてるからって使わない方がいいのかもしれないですね。

image.png

ここまで来たらこっちのもんです、適当に情報設定するためのクラスを定義します。例えば以下のように

public class Info
{
    public string Name { get; set; }
}

そして local.settings.jsonInfo:Name というキーで適当な値を設定します。

local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "Info:Name": "Hello world" 
  }
}

そして Startup.cs で AddOptions メソッドで登録します。

Startup.cs
using FunctionApp2;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(Startup))]

namespace FunctionApp2
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddOptions<Info>()
                .Configure<IConfiguration>((info, configuration) => configuration.Bind("Info", info));
        }
    }
}

ここまでおぜん立てすると関数で利用できます。例えば、この Info の Name をそのまま返す関数を作るとこんな感じです。

Function1.cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace FunctionApp2
{
    public class Function1
    {
        private readonly IOptions<Info> _info;

        public Function1(IOptions<Info> info)
        {
            _info = info;
        }

        [FunctionName("Function1")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation(_info.Value.Name);
            return new OkObjectResult(_info.Value.Name);
        }
    }
}

実行してエンドポイントを叩くとこんな感じの結果になります。思った通りですね。

image.png

Azure にデプロイした後は、Function App の構成に Info__Name のように local.settings.json では : 区切りで登録したものを以下のように __ 区切りで登録します。

image.png

エンドポイントを叩くと以下のようになりました。ちゃんと値が取れてますね。

image.png

いい感じ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

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

題材

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

class Program
{
  static void Main(string[] args)
  {
    var User=new UserInfo(new List<string>{"012","user","pass","xx@xx.com"});
  }

  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;}
  }
}

前準備 添字でアクセス

class Program
{
  static void Main(string[] args)
  {
    var User=new UserInfo(new List<string>{"012","user","pass","xx@xx.com"});
    //添字でアクセス
    User["ID"]="dummy";
    if(User.ID=="dummy"){
      //成功
    }
  }

  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(クラス名).GetProperty(propertyName).GetValue(this)

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

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

コンストラクタ

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

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

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

下記をUserInfoクラスに追加

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]の添字に変換します。
これにより、インデクサでのアクセスが出来るようになります。

全体像

class Program
{
  static void Main(string[] args)
  {
    var User=new UserInfo(new List<string>{"012","user","pass","xx@xx.com"});
    //添字でアクセス
    User["ID"]="dummy";
    if(User.ID=="dummy"){
      //成功
    }
    Console.WriteLine(User[2]);
    //pass
    foreach(var name)
    {
      Console.WriteLine(User.ToList());
      //012,user,pass,xx@xx.comの順に表示される
    }
  }

  public class UserInfo
  {      
    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 List<string> ToList()

thisではリストを返さないため、別途リスト取得用のメソッドを設けています。

参考

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

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

題材

下記の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(クラス名).GetProperty(propertyName).GetValue(this)

↑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#】プロパティ名でプロパティにアクセスする

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む