かきスタンプ

福岡でフリーランスの物流系のエンジニアやってます。

Oracle(PL/SQL):配列型の引数に、値を設定してデバッグする

Oracle開発ツールのいくつかは、PL/SQL の引数が配列の場合、自由に値がセットできなくて、苦労するケースもあるかと思います。
 
Oracle SQL Developer のデバッグ実行にて、『PL/SQL ブロック』を編集することで、配列型の引数に、好きな値を設定する事ができます。

f:id:kakisoft:20180510224409p:plain

WPF:DataGrid の ItemsSource に、配列データを設定すると妙な出力結果になるんで、その場合は ListView を使おうという話

郵便番号/住所/緯度経度データ等の地理情報を、XML or JSON で取得できるサービス『HeartRails Geo API』にて、エリア情報を叩くと、こういう値が返ってきます。

{
    "response": {
        "area": [
            "北海道",
            "東北",
            "関東",
            "中部",
            "近畿",
            "中国",
            "四国",
            "九州"
        ]
    }
}

この結果を、グリッドの ItemsSource に流し込んで、いい感じに表示しようと思い、以下のように書いたら、何とも微妙な結果になりました。  
 
Http リクエストを投げるところと、デシリアライズのところは省略しています。
また、受け側は dynamic型にしています。
(フォーム部分は省略しています。といっても、「myDataGrid01」という Name の DataGrid があれば何でもいい訳ですが。)

csソース1
List<dynamic> areaList = new List<dynamic>();
foreach (var item in responseData.response.area) // 「responseData」にデシリアライズされたデータが格納されています。
{
    areaList.Add(item);
}
myDataGrid01.ItemsSource = areaList;
実行結果1

f:id:kakisoft:20180430193003p:plain  
余計なものが色々入ってます。 必用なのは Valueなので、指定して抽出。

csソース2
List<dynamic> areaList = new List<dynamic>();
foreach (var item in responseData.response.area)
{
    areaList.Add(item.Value);
}
myDataGrid01.ItemsSource = areaList;
実行結果2

f:id:kakisoft:20180430193006p:plain  

なぜか Lengthが取れるという妙な結果に・・・。
json のパースの仕方がどうこうという訳でなく、DataGrid の ItemsSource に、配列を放り込むと、こうなるみたいです。
なので、List<string> のデータでも、同様の現象が起こります。

対策

どうしても DataGridで表現しなければならないなら、配列の部分を Dictionaryにする or 自作のクラスを定義して、それに放り込むかですが、本来のデータに不純物を入れ込む事になるので、ちょっと避けたい。

という訳で、こういった場合は DataGridでなく、ListView を使う方法が最良ではないでしょうか。
以下では、「myListView01」という Name の ListView を定義しています。

csソース3
List<dynamic> areaList = new List<dynamic>();
foreach (var item in responseData.response.area)
{
    areaList.Add(item);
}
myListView01.ItemsSource = areaList;
実行結果3

f:id:kakisoft:20180430193009p:plain  
 
 
DataGrid は色々できて便利なんですが、その分操作が難しかったり、変にバッドノウハウを知っておかないとハマる原因になったりするので、やる事がシンプルなら、ListViewでいい気がします。

C#:DBから取得したModelのリストを、Modelを継承した要素で表現する

こういう状況。

  • Model定義されたクラスがある
  • Model のデータは、DBなどから参照し、List にしている
  • List の中身を、Model を拡張したクラスで表現したい(画面制御のみで使用するプロパティを付与したい)
(例)
List<Users>        //Model(のリスト)
List<ExtendUsers>  //Modelを拡張したクラス(のリスト)

こういうのがあって、List<ExtendUsers> に、List<Users> の要素をブチ込みたい、といったケース。

ストレートにダウンキャストが使えないんで、以下のような工夫をしてみた。
 
分割しているのは、全部繋げるとスクロールバーが一番下にしか来なくて、読みづらかったためです。

//親クラス
class Users
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Position { get; set; }
}
//子クラス
class ExtendUsers : Users
{
    public bool IsChecked { get; set; } //画面の制御用として、子だけで使いたいプロパティ

    public ExtendUsers(Users value) //コンストラクタの引数に、親のインスタンスを渡す
    {
        //---------------------
        //  親要素の全プロパティをリストアップし、子に同じ値を設定
        //---------------------
        PropertyInfo[] propertyInfoinfoArray = value.GetType().GetProperties();  //プロパティをリストアップ
        foreach (PropertyInfo item in propertyInfoinfoArray) //リストアップしたプロパティをループで回す
        {
            var property = value.GetType().GetProperty(item.Name);  //プロパティを取得
            property.SetValue(this, item.GetValue(value));          //子に親と同じ値をセット
        }
    }
}
//Model定義されたクラスのリスト(ここに書いてると、そう見えないけど、そういう事にしといて下さい。)
private List<Users> _users;
//Model定義されたクラスを拡張した要素を詰め込んだリスト
private List<ExtendUsers> _extendUsers;

private void MyButton01_Click()
{
    _extendUsers = new List<ExtendUsers>();
    foreach (var item in _users) //Model定義された要素が入ったリストをループ回す
    {
        ExtendUsers el = new ExtendUsers(item); //子のインスタンス作成時、親のインスタンスを引数に渡す。(詳細は上記を参照)
        _extendUsers.Add(el); //親のインスタンスと同じ値を設定した子を、リストに追加
    }
}
//============================
// サンプルソースを動かすために用意した。本当はDBから引っ張ってくる
//============================
private void SetUsersList()
{
    _users = new List<Users>();
    _users.Add(new Users { Id = 1, Name = "Tanaka", Position = 1 });
    _users.Add(new Users { Id = 2, Name = "Yamada", Position = 1 });
    _users.Add(new Users { Id = 3, Name = "Watanabe", Position = 2 });
}
概要
  • 親要素が入ったリストをループで回している
  • 子のインスタンスを作成する時、コンストラクタに親のインスタンスを渡している
  • コンストラクタにて、親のプロパティの一覧を精査し、同じ値を子に設定している

 
 
もっといい方法がありそうだけど、今の自分にはこの辺が限界。

C#:アップキャストとダウンキャストについて、サンプルソース付きで解説してみる

f:id:kakisoft:20180429085405p:plain

  • アップキャストは、常に安全に行える
  • ダウンキャストは、エラーが発生する事がある。  
     
※ 解説 ※
  • キャストは型を変更するだけで、中身が消える訳ではない。
    (アクセスできる範囲が変わるだけで、実態は存在している)
  • インスタンス作成時、メモリに領域が割り当てられる。
  • 子クラスのインスタンスは、親クラスのインスタンスより多くの領域を必用とする。
  • 親→子 とキャストした場合、子クラスが必要とする領域に、メモリが割り当てられていない状態となる。
    (そのため、エラーとして弾いている。)

 
 
以上を踏まえて、サンプルソースで説明。

//親クラス
class ParentClass { }
//子クラス
class ChildClass : ParentClass { }

private void MyButton01_Click()
{
    //===========================
    //      アップキャスト
    //===========================
    ParentClass parent01;
    ChildClass child01;

    //子クラスのインスタンスを生成
    child01 = new ChildClass();

    //子クラスのインスタンスを、親クラスに代入可能。
    parent01 = child01;


    //===========================
    //  ダウンキャスト(エラー)
    //===========================
    ParentClass parent02;
    ChildClass child02;

    //親クラスのインスタンスを生成
    parent02 = new ParentClass();

    //キャストできるかどうか確認(falseになります)
    if (parent02 is ChildClass)
    {
        //キャスト時にエラーが発生する
        child02 = (ChildClass)parent02;
    }

    //asを使えば キャストできない場合 nullが入る
    child02 = parent02 as ChildClass;


    //===========================
    //     ダウンキャスト
    //===========================
    ParentClass parent03;
    ChildClass child03;

    //親クラスのインスタンスを、子クラスで生成
    parent03 = new ChildClass();

    //ダウンキャスト可。
    child03 = (ChildClass)parent03;
}

C#:ネット上で一番簡単な、async/await を使用した非同期処理の説明とサンプル

非同期処理にて使用する async/await の超簡単な説明

  • 非同期メソッドには async キーワードを付ける。
  • 呼び出し先が async void の場合、呼び出し元に awaitは不要
  • 呼び出し先が async Task の場合、呼び出し元に awaitを記述する。
  • Task<T> は T の型が返る。(例:Task<string> は string が返る)
  • Task で取得した値を取り出すには、await を使用する。
  • 非同期メソッドの末尾は「Async」とする(慣習)

 
 
以下、ボタンを押したら google.co.jp の内容を取得するプログラムです。
フォーム側は WPFWindows Forms あたりで適当に用意して下さい。

サンプルコード

private void Button01_Click(object sender, RoutedEventArgs e)
{
    //呼び出し先が async void の場合、呼び出し元に awaitは不要
    Button01_ClickContentAsync(); 
}
//非同期メソッドには async キーワードを付ける。
private async void Button01_ClickContentAsync() 
{
    string targetURL = "http://www.google.co.jp/";

    //呼び出し先が async Task の場合、呼び出し元に awaitを記述する。
    await HttpGetRequestAsync(targetURL); 
}

private async Task HttpGetRequestAsync(string targetURL)
{
    using (var _httpClient = new HttpClient())
    {
        //Task<string> は string が返る
        Task<string> response = _httpClient.GetStringAsync(targetURL); 
        //Task で取得した値を取り出すには、await を使用する。
        string contents = await response; 

        Console.WriteLine(contents);
    }
}

 
初めのうちは、「async」って何?(Microsoft Docsを読む)、「await」って何?(Microsoft Docsを読む)、「Task」って(略)
・・・と、構文1つ1つを調べながら進めていくより、『非同期処理にて使用する構文』と、ひとまとめにして読み進める方が、理解しやすいんじゃないかと思います。  
 
 
非同期処理について調べていると、ディープな世界に踏み込んでいったり、過去の歴史まで遡りながら解説しているサイトが多く、
「理論は後でちゃんと学ぶから、まず、どんなコード書けばいいの?」という人向けの記事が少ないなー、と思ったんで、エントリにしてみた。

WPF:Grid上の好きなポジションに、動的に要素を配置

System.Windows.Controls.Grid は、Grid.Row と Grid.Column にて、要素のポジションを指定します。
 
動的に要素を配置する場合、SetValue にて、Grid.RowProperty と Grid.ColumnProperty を設定するとOKです。

実行例

f:id:kakisoft:20180410001143p:plain

ソース

xaml

<Window x:Class="PracticeWPF.MyWindow19"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:PracticeWPF"
        mc:Ignorable="d"
        Title="MyWindow19" Height="200" Width="200">
    <Grid>
        <Grid x:Name="myGrid01" Width="150" Height="150">
            <Grid.RowDefinitions>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>
        </Grid>
    </Grid>
</Window>

cs側

using System.Windows;
using System.Windows.Controls;

namespace PracticeWPF
{
    /// <summary>
    /// Gridの指定位置に要素を追加
    /// </summary>
    public partial class MyWindow19 : Window
    {
        public MyWindow19()
        {
            InitializeComponent();

            SetGridItems();
        }

        private void SetGridItems()
        {
            Button b0_0 = new Button();
            b0_0.Content = "0-0";
            b0_0.SetValue(Grid.RowProperty, 0);
            b0_0.SetValue(Grid.ColumnProperty, 0);
            myGrid01.Children.Add(b0_0);

            Button b0_2 = new Button();
            b0_2.Content = "0-2";
            b0_2.SetValue(Grid.RowProperty, 0);
            b0_2.SetValue(Grid.ColumnProperty, 2);
            myGrid01.Children.Add(b0_2);

            Button b1_1 = new Button();
            b1_1.Content = "1-1";
            b1_1.SetValue(Grid.RowProperty, 1);
            b1_1.SetValue(Grid.ColumnProperty, 1);
            myGrid01.Children.Add(b1_1);

            Button b2_2 = new Button();
            b2_2.Content = "2-2";
            b2_2.SetValue(Grid.RowProperty, 2);
            b2_2.SetValue(Grid.ColumnProperty, 2);
            myGrid01.Children.Add(b2_2);
        }
    }
}