vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

dotnetConf 関西2017に参加してきました

はじめに

10/14に日本マイクロソフト関西支店で行われた、dotnetConf関西 2017に参加してきました。

connpass.com

4セッション + LT大会で、バラエティ豊かな内容を聴くことができました。

聴き逃しや勘違いなどもあるかとは思いますが、聴きながら書き留めたメモを中心に書き残しておきます。
(修正などはご指摘いただければ対応します)

またスライドは後から公開されたものがあればリンクを追加する予定です。

.NETの今と未来~デバイス&クラウドネイティブを目指して

dotnetConfについてや、セッションのタイトル通り15年前!に登場した.NETが今どう変わっているか、今後どのように進んでいくか、
ということが紹介されました。

2017/10/22更新
dotnetConf関西2017のものに差し替えました

www.slideshare.net

ここからメモ


dotnetConfについて

dotnetConfはオンラインが中心。ただし今回のようにローカルイベントも世界各地で行われている。

channel9.msdn.com

Twitterでの盛り上がりはマイクロソフト本社にも伝わる。そのためどんどんツイートしてほしいとのこと。

マイクロソフト社の活動としてはAzureがメインになってきている。
ただし.NETは.NETで変わらず活動していく。

.NET Framework、.NET Core

Windows上で動作する .NET Framework (現行ver.4.7)と、
マルチプラットフォームで動作する .NET Core (現行ver.2.0。ベースの一部はMono)。

これらは今後も統合されるようなものではなく、それぞれ進化していく。

ただし.NET Frameworkの資産を .NET Core、 Xamarin でも活用できるように、
共通化( .NET Standard ?)も進めていく。

実装は C# がメインであり、最初に実装されはするが、 VB.net 、 F# もしっかりサポートしていく( .NET Framework、 .NET Core 共に)

Xamarin

Xamarinには2種類の作り方がある。

  • Xamarin Native -> UI部分はそれぞれのプラットフォームに合わせて作り、共通処理をひとまとめ
  • Xamarin Forms -> UI部分から共通。ただしプラットフォームによって制限もあり?

どちらで開発するにしても、iOS開発にはXCodeが必要。

Xamarin Live Player を使うと、 Visual StudioiOSバイスをペアリング -> Visual Studio で Xamarin.iOSデバッグが可能。

ただし XCode でビルドした状態と全く同じ、というわけではないので最終出力する部分は MacXCode が必要。

.NET Standard

.NET Standard は、 .NET Framework 、 .NET Core 、 Xamarin で共通で利用できるコード。

ver.2.0で2万以上のコードが共通化された。

利用方法としては、共通化させたいコードを .NET Standard ライブラリとして切り出す -> ライブラリとして使用可能
( Nuget パッケージも同時作成)

Container + Docker

現在はCloud上にあらかじめ用意されている機能・サービスを活用していく Cloud Native が中心になってきた。

App service on Linux & Web App for Containers

今までベース部分のOSはWindowsだったが、Linux を使うものが登場した(App service on Linux)。

コンテナでランタイムを実装する -> コンテナさえ動くようにすれば、どこでも動かすことができるように

Write-once, Run-anywhere

Containerを使う上で必要なファイルも Visual Studio で生成・編集できるように。

Visual Studio 2017 では Docker を利用する機能が内包されている。
通常のビルドと同じような操作で Docker のビルドをすることができる。

Serverless

Azure Functions -> AWS の Lambda のような、Serverless を実現する機能。

Functions は Visual Studio で、 .NETC# を使って開発可能。

動作するのはユーザーからトリガーを引くための操作が行われた場合。

ローカルで動かしている.NETコードを基本そのままクラウドに上げることができる

よりモダナイズされた環境での開発・サービス提供を


ここまで

感想

.NET って本当に幅広いんだなぁ(こなみかん)

お話の中で特に気になったのは .NET Standard と Azure でした。

.Net Standard は、例えば自分の普段の作業では Unity と UWP で処理を共通化させる、といったことができそうです。

また、処理を共通化させることができる、という意味ではネイティブだけでなく、 Xamarin にも取り組んでみようかなぁ。

あと Azure はそれ自体も気になるところですし、 Functions も C# で書くのであれば、
AWS Lambda よりも情報を集めやすそうな気がします。
( AWS Lambda では C# がメインの言語ではないため、
他の言語の情報を変換する必要があると思うので)

お試し枠もあるようなので、こちらも近いうちに触ってみたいと思います。

Visual Studio拡張とRoslynとDotNet.exeなどいろいろ

Visual Studio拡張機能を作成した時にハマったあれこれが紹介されました。

2017/10/22更新
dotnetConf関西2017のものに差し替えました

www.slideshare.net

ここからメモ


拡張:Extensibility -> VSIXプロジェクト

下位互換性をもたせたい場合も、最新(Max ver)のVSで作成する

右クリックでメニューを追加したい場合、Custom Commandを追加し、実装する

ファイル名がすべてCommand名と共通のものになるため、全体に関連するファイルなどはリネームしたほうが良い

例)
  • RClickCommandPackage.vsct -> ExTest.vsct
  • RClickCommandPackage.cs -> ExTestPackage.cs

ドッキングウィンドウの追加は Custom Command Window?を使う

VS2017でしか使えないパッケージが含まれていてVS2015で使った瞬間クラッシュした


VS2015で作るとVS2017にはインストールできない

関数の型を調べるためにリフレクションを使おうとすると、VSがdllを開きっぱなしにしてしまい、
ビルド時?にエラー(Warning?)が出るので拡張を作る上では問題がある


ここまで

感想

Visual Studio を使って Visual Studio拡張機能を作成する、というのはまだツラいところがあるのだなぁ
(最新版の Visual Studio が出るたびにビルドし直す必要があったり、プロジェクトのテンプレートにゴミが入っていてエラーになったり)
というのが正直な感想ではあります(´・ω・`)

ただ、ここも今後改善されてはくるのだろうと思いますし、
やっぱり自分の使い方に合わせて機能を追加していけるのは良いと思うので、自分としても挑戦はしてみたいなぁ、とも思いました。

また、紹介されていた拡張機能も試してみたいところ。

.NET Standard入門

最初のセッションでも紹介された、 .NET Standard についてガッツリ紹介されました。

www.slideshare.net

ここからメモ


.NET Standard は、 .NET Framework 、 .NET Core 、 Xamarin のどれかだけにべったり依存したものではない。

一般的には可能な限り最小バージョンの .NET Standardを使うのが推奨される。

最適なバージョンは Visual Studio 側で静的に見てくれるわけではないため、
バージョン指定 -> コンパイル -> エラーが出たらバージョンを上げる
という作業を繰り返す必要がある。

実際にはライブラリを作るときに.NET standardが利用される。

  • Shared library - Assemblyを共有しない。共有プロジェクト(ソースコードレベルの共有)
  • PCL - 今はあまり使われていない
  • .NET Standard - Assemblyを共有

今後は .NET Standard を使うことが推奨される?

PCL は .NET Standardの各バージョンと互換性がある。
足りないものはNugetでとってきて解決する。

Visual Studio 2017 Update4 からは .NET Standard2.0 のインストールをしなくても使える、らしい。

dnSpyでデコンパイル

(dnSpyについてはこの辺が参考になりそう?)

https://qiita.com/NetSeed/items/54fbf30cb21c77c05c41

dllでは型が定義されているのではなく、 TypeForwardedTo でアトリビュートで指定されているだけ

同じString型でも、 WindowsAndroid などターゲットに応じて全く別のクラスを参照している
(違いは.NET Coreが吸収する)

最終的には .NET Core の Library を参照するわけだが、そこまでの過程はプラットフォームごとに異なっている。

Nuget Package を参照したクラス?ライブラリを参照した Console App を実行するとエラーでクラッシュする ↓ 実行時に必要なライブラリもファイルを移動しないため

ValueTuple は .NET Framework4.7 から使用できる。 ただし、4.6の場合も .NET Standard で定義してそれを読み込むと.NET Framework からでも使用できる。

ただし、dllファイルを大量に引き連れてきてしまうので注意。


ここまで

感想

自分の実力的に理解しきれなかったところがたくさんあった、
というのが正直なところですが、公開された資料やお話の中にあったキーワードを元に、
中身を追いかけていこうと思います。

また、ググった感じでは Unity で .NET Standard のライブラリを作る、利用する、といった情報は少ないようですが、
こちらも試したいところ。

Introducing Fluent Design System あるいは Metro の先を紡ぐ手がかり

スキューモーフィズムから Metro (Modern UI)を経て、
Hololens などの Mixed Reality などにも対応する、
Fluent Design について紹介されました。

2017/10/22更新
スライドのリンクを追加しました

www.slideshare.net

ここからメモ


スキューモーフィズム -> Metro -> UWP(PCやスマホだけでなく、ラズパイやHololens)にも対応

Hololensの登場により、UIが画面の外に出てくるようになった

Fluent Design * Project Neon Fall Creates Updateで利用可能 * Light、Depth、Motion、Material、Scaleの5つの要素 * コンテンツが繋がっていくデザイン * 3D時代のWindowsのためのデザインシステム * フラットでもなく、スキューモーフィズムでもない、物質の本質を表現する

XamlでAcrylicBrush要素を使うことでアクリルブラシが使用可能に (アクリル板のように半透明になるイメージ)

Lightはマウスカーソルを光源?としてボタンなどにライトを当てることができる

MR Design Lab: UIサンプル

github.com

色遣いも決まりがある。

半透明とはいえ、Vista時代のものとは意味が異なっている


ここまで

感想

Fluent Design については、一番普段の仕事に近いのに全く知らなかったため、
早くキャッチアップせねば、という気持ちです(;´Д`)

最近(というほどでもないけど)登場したデザインとしては他に Material Design がありますが、
テイストなどは異なるものの、紙や光など自然界にあるものを表現する、
という部分に共通点があるのかな、などとぼんやり思いました。

LT

本編も濃ければLTも濃い。

あまり書き留めることはできませんでしたが、どれも聴きどころ満載な感じでしたw

- Manga-Yonda!!

www.slideshare.net

ここからメモ


XAML条件分岐 

今までは XAML の中で条件分岐を表現するのは難しかった

blog.tmyt.jp

現在は Conditional XAML を使うことで、条件分岐が使えるようになった。

が、制限はあり、C#でifを書くようには使えないっぽい

Xamarin

Xamarin NativeでもMVVMCrossなどを使うことでDataBindingが使える

Azure Machine LearningでCNNを使って二次元の顔判定

Azure Machine LearningではGUI機械学習ができる

学習に24時間以上かけられない、という制限がある

その他

www.instagram.com

なお懇親会にも参加させてもらいましたが、
持ち前のコミュ障を発揮してあまりお話することができずorz

ま、まぁこの辺は次回リベンジということで。

あとお話を聴いているだけでも楽しかった、ということは付け加えておきます。

おわりに

実は .NET 関連の勉強会は初めての参加でしたが、
参加されている方や雰囲気もどことなく違っていて新鮮でした。

.NET Standard や Azure など、気になる情報もたくさん得られたので、
時間はかかるかもですが一つずつ試してみようと思います。

スタッフの皆様、参加された皆様、会場やWifiなどを提供いただいたマイクロソフト様、ありがとうございました!

最後に...

【C#】Taskをキャンセルする

はじめに

前回に引き続き、async / await / Task ネタです。

非同期で処理している内容をストップするにはどうするの?というお話。

Task.Runの中で処理を止める

Task.Run の中で、条件に応じて処理を途中で止める、というのは比較的簡単です。

private async void CallAsyncMethod()
{
    var myTask = await GenerateTextAsync();
    // GenerateTextAsync() の処理が完了したら実行される.
    Debug.Log(myTask);
}
private async Task< string> GenerateTextAsync()
{  
  return await Task.Run< string>( () => {

    if(何かの条件)
    {
      return "Canceled";
    }
  

    Thread.Sleep( 3000 );
    const string sampleText = "Hello\nworld\nおはようございます!\n";

    return sampleText;
  } );
}

普通の処理と同じく、早期リターンするか後の処理を if でくくって Task を完了させてしまえば良いですね。

Task.Runの外から処理を止める

では Task.Run の外側から処理を止めるにはどうするか。

感覚的には Task.Cancel とかすれば良い気がしたのですが、そのようなメソッドはありません。

方法としては、
1. Task.Run の第二引数として、 CancellationToken という Token を渡します。 2. Task.Run の外側(処理を止めたいタイミングで) CancellationToken.Cancel() を実行します。 3. Task.Run のなかで CancellationToken.IsCancellationRequested が True かどうかを確認し、 True なら処理を止めます。

using UnityEngine;
using UnityEngine.UI;
using System.Threading;
using System.Threading.Tasks;

public class MainController : MonoBehaviour {
    public Text ResultText;
    private int flag;
    private void Start ()
    {
    
    // 非同期処理をCancelするためのTokenを取得.
        var tokenSource = new CancellationTokenSource();
        var cancelToken = tokenSource.Token;
        

        CallAsyncMethod(cancelToken);
        Debug.Log("Start()");

  
    // 処理をキャンセル.
        tokenSource.Cancel();
    

    }
    private async void CallAsyncMethod(CancellationToken cancelToken)
    {       
        var myTask = await GenerateTextAsync(cancelToken);
        Debug.Log(myTask);
    }
    private async Task GenerateTextAsync(CancellationToken cancelToken)
    {
        var context = SynchronizationContext.Current;

        return await Task.Run( () => {
            Thread.Sleep( 1000 );

        
            if (cancelToken.IsCancellationRequested)
            {
                Debug.Log("Canceled");
                // キャンセルされたらTaskを終了する.
                return "Canceled";
            }
      

            const string sampleText = "Hello\nworld\nおはようございます!\n";

            Thread.Sleep( 2000 );

            context.Post((state) =>
            {
                ResultText.text = sampleText;
            }, cancelToken);
            return sampleText;
        }, cancelToken);
    }
}

回りくどい気もしますが、 どのような処理を行っているかを確認せず、いきなり強制終了するな、ということなのではないでしょうか。

Token を、 GenerateTextAsync を呼んでいる CallAsyncMethod() ではなく、さらに上流となる Start() で生成・渡しているのは、
前回書いた通り await を使って非同期処理を呼ぶと、それ以後の処理は非同期処理が完了するまで実行されないためです。

なお、処理がキャンセルされたときに例外を投げたい場合は、 cancelToken.ThrowIfCancellationRequested() を使ってシンプルに書くことができます。

if (cancelToken.IsCancellationRequested)
{
  Debug.Log("Canceled");
  // キャンセルされたら OperationCanceledException を投げる.
  cancelToken.ThrowIfCancellationRequested();
}

注意すべき点としては、キャンセルされたときに処理を止める、という処理は自分で書かないといけない、という点です。
あくまでもキャンセルされたことが Task.Run の中で判別できるようにする、という仕組みのようなので。

おわりに

Task がキャンセルされうる、というのは引数に Token を渡すことで判断はできるのですが、
本当にキャンセル処理が含まれているか、というのは静的に確認できると良さそうな気はしました
(とはいえキャンセルフラグが立ったときに、必ずしもその場で処理をストップするとは限らないので難しいかもですが)。

まだちゃんと調べられてはいませんが、 Task は別の Task とまとめたりもできるようなので、
見通しが悪くならない程度に細分化して、必要な処理が揃っているかを確認する、というのが良いのかもしれませんね。

参照

【C#】Unityでasync / await

はじめに

Unity2017以降、C#6の機能を使うことができるようになりました。

今回のテーマである async / await はモバイル環境だとまだ課題があるようですが、
とにかく触ってみることにしました。というお話。

準備

Unity2017.1.1f1 時点では、 C#6 (というか .net 4.6)はデフォルトでは有効になっておらず、
Experimental という扱いになっています。

有効にするには、 Player Settings > Other Settings > Configuration > Scripting Runtime Version を、
Experimental(.Net 4.6 Equivalent) に切り替えて、 Unity Editor を再起動します。

非対応

…とここまでワクテカしながら読み進めてきた方がいましたら残念なお知らせなのですが、
Unity のクラス(というか MonoBehaviour を継承しているクラス)のメソッドは、
今まで通り MainThread 以外からの実行はできません。

後述しますが、 SendMessage や ExecuteEvents.Execute も、定義しているクラス自体は MonoBehaviour を継承していないものの、
別 Thread から実行するとエラーになります。
(おそらく最後、指定したメソッドを実行するところでエラーになっているのではないかと思います)

ということで、ファイルの読み込みや HttpClient など、時間のかかる、かつ C# の機能を使って行われる処理に対して使うことができる状況です。

なお UniRx と組み合わせるとより便利になりそうではあるのですが、
今回はそのまま使ってみることにします。

とにかくやってみる

ということでまずは使ってみましょう。

なお async / await / Task の使い方は参照のリンク先におまかせします(丸投げ)。

using UnityEngine;
using UnityEngine.UI;
using System.Threading;
using System.Threading.Tasks;

public class MainController : MonoBehaviour {
    public Text ResultText;
    private void Start ()
    {
        CallAsyncMethod();

    // CallAsyncMethod() を呼び終わったら(処理の完了を待たずに)実行される.
        Debug.Log("Start()");
    }

    private async void CallAsyncMethod()
    {
        var myTask = await GenerateTextAsync();
        // GenerateTextAsync() の処理が完了したら実行される.
        Debug.Log(myTask);
    }

    private async Task< string> GenerateTextAsync()
    {
    // 非同期処理を定義して返す.        
        return await Task.Run< string>( () => {
            // 三秒間だけ待ってやる.
            Thread.Sleep( 3000 );
            const string sampleText = "Hello\nworld\nおはようございます!\n";

            Debug.Log("GenerateTextAsync()");
            return sampleText;
        } );
    }
}
  • Task を返す GenerateTextAsync() を呼び出すとき、 await をつけ忘れて myTask.Result とかしてしまうと、
    Unity Editor がフリーズするので気をつけましょう。
  • Debug.Log が実行される順番は 1. Start() 2. GenerateTextAsync() 3. myTask ( GenerateTextAsync() の戻り値)です。
  • Debug.Log は Unity の処理ですが、別 Thread から呼び出しても特にエラーにはなりません。

async の Unity 定義メソッドへの適用

await をつけて GenerateTextAsync() を呼ぶためには、そのメソッドに async をつける必要があります。

これは Start() など Unity のメソッドにも適用できます。

ただし、非同期処理を呼んだ後の処理は(例: CallAsyncMethod() の Debug.Log() )、それが完了するまで呼ばれないため、
上記のように別のメソッドに切り分けたほうが良いと思います。

TaskからMainThreadを呼ぶ

さて、前述の通り、 GenerateTextAsync() の Task.Run< string> の中で ResultText (UnityEngine.UI.Text) のテキストを変更することはできません。

Task からこのような処理を行うにはどうすれば良いでしょうか。

Androidには別 Thread から UIThread を呼び出す方法があります。

mainActivity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        // MainThread での処理.
    }
});

これと同様の仕組みが、 C# にも存在します。

using UnityEngine;
using UnityEngine.UI;
using System.Threading;
using System.Threading.Tasks;

public class MainController : MonoBehaviour {
    public Text ResultText;
    private void Start ()
    {
        CallAsyncMethod();
  }

    private async void CallAsyncMethod()
    {
        var myTask = await GenerateTextAsync();
    }

    private async Task< string> GenerateTextAsync()
    {
    
    // MainThreadのコンテキストを取得.
        var context = SynchronizationContext.Current;
    

        return await Task.Run< string>( () => {
            Thread.Sleep( 3000 );
            const string sampleText = "Hello\nworld\nおはようございます!\n";


      // MainThreadのコンテキストを通して、Textを変更する.
            context.Post((state) =>
            {
                ResultText.text = sampleText;
            }, null);
      
            return sampleText;
        } );
    }
}

SynchronizationContext を使って MainThread のコンテキストを取得することで、
別 Thread から Unity の( MainThread からの実行が必要な)処理を実行することができます。

おわりに

C#6 の機能が使えるようになったことで、細かい部分でも色々便利になって良いですね☺

async / await は、将来的に Unity の処理にも使うことができるようになるのかはわかりませんが、
時間のかかる処理を行う場合には是非とも活用していきたいところです。

とりあえず非同期処理のかんたんなところに触れてみましたが、
もう少し突っ込んで触ってみたくもあります。

ということで、次回に続く。。。かもしれない。

参照

【C#】横書き -> 縦書き変換

はじめに

Twitterにてちょっと話題になった、テキストを縦書きで投稿するためのメモです。

今回はテキストを固定にしていますが、Unity、WPFなどで入力元、出力先を指定してやれば動的に生成したり、
Twitterなどにそのまま投稿することもできます。

縦に書く

TextViewなどの機能を使う場合は別ですが、
文字列を縦に並べるには単純に文字列を一文字ずつに区切って、それを縦に並ぶよう置き換えるのが良さそうです。

なお列の区切りは改行文字とします。

まずは一文字ずつに区切り、ついでに全角・半角文字が混ざると位置がずれてしまうので、半角文字の場合はスペースを追加することにします。

// 元のテキスト.
const string sampleText = "Hello\nworld\nおはようございます!\n";
// 改行文字で区切る.
var splittedSamples = sampleText.Split('\n');

// ToCharArray()で一文字ずつ切り出し -> charからstringに戻す -> 半角文字にスペース追加.
var results = splittedSamples.ToList()
    .Select(samples => samples.ToCharArray()
        .Select(sample => sample.ToString())
        .Select(sample => Regex.Replace(sample, @"[a-zA-Z0-9|\.\-\\\,]", " " + sample))
        .ToList()).ToList();

これで一文字ずつ切り出して、一行ずつにまとめた List< List< string>> の値となります。

なお、長音の縦横置き換えなどは行っていないため、必要に応じて追加してください。

あとはこれを頭から並べていきます。

const string sampleText = "Hello\nworld\naaa\nbbb\n";
            
var splittedSamples = sampleText.Split('\n');

var results = splittedSamples.ToList()
    .Select(samples => samples.ToCharArray()
        .Select(sample => sample.ToString())
        .Select(sample => Regex.Replace(sample, @"[a-zA-Z0-9|\.\-\\\,]", " " + sample))
        .ToList()).ToList();

var resultMaxCount = results.Select(samples => samples.Count).Max();

var resultText = "\n";
for (var i = 0; i < resultMaxCount; i++)
{
    for (var j = results.Count - 1; j >= 0; j--)
    {
        // 列の間に全角スペースをはさむ.
        resultText += "  ";
        // その列に文字がなかった場合は全角スペースに置き換え.
        resultText += (results[j].Count - 1 >= i) ? results[j][i] : "  ";
    }
    resultText += "\n";
}

せっかくなのでこちらも Linq で解決したいところでしたが、
良い方法が思いつかなかったのでfor文を使うことにしました。

また、Twitterに投稿する場合に、一行目の最初の文字より前に入っているスペースが取り除かれてしまうようです。
それを防ぐため、頭に改行を挟んでいます。

参考

C#で CSV -> Json を作る

はじめに

前回PythonでCSVからJsonを作るというのをやりましたが、
ふとC#(Unityではなく)でやってみたらどうなるんだろう、と思ったのでやってみました。

CSVを読み込む

CsvReader.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace CsvConverter
{
    public class CsvReader
    {
        public List ReadCsv()
        {
            using (var reader = new StreamReader(@"parts.csv", Encoding.UTF8))
            {
                var partsList = new List();
                // 1行目はスキップ.
                reader.ReadLine();
                    
                while (reader.Peek() > -1)
                {
                    var readText = reader.ReadLine();
                    if (readText == null)
                    {
                        continue;
                    }
                    var splitTexts = readText.Split(',');
                    if (splitTexts.Length < 3)
                    {
                        continue;
                    }
                    var newParts = new Parts
                    {
                        PartsNo = splitTexts[0],
                        PartsName = splitTexts[1],
                        Description = splitTexts[2],
                    };
                    partsList.Add(newParts);
                }
                return partsList;
            }
            return null;
        }
    }
}

Jsonファイルとして出力

Parts クラスのリストを Json に変換するには、UniRxでいつもお世話になっている neueccさんの DynamicJson を使用しました。

http://dynamicjson.codeplex.com/

シンプルな使い勝手ながら、しっかりとドキュメントも用意されていて大変ありがたい限りですm(__)m

唯一はまったのが、変換元のクラスの変数は、プロパティを持つ必要がある、ということです。

MetaParts.cs (失敗)

public class MetaParts
{
    public string ModelName;
    public List PartsList;
}
  • この場合、正しく変換できず空の Json ができてしまいます。

正しくは。。。

MetaParts.cs

public class MetaParts
{
    public string ModelName { get; set; }
    public List PartsList { get; set; }
}

変換自体は驚くほどに簡単です。

JsonCreator.cs

using System;
using System.IO;
using System.Text;
using Codeplex.Data;

namespace CsvConverter
{
    public class JsonCreator
    {
        public string Create(MetaParts parts)
        {
            // MetaPartsクラスのオブジェクトをJsonに変換して返す.
            return DynamicJson.Serialize(parts);
        }
        public void Output(string jsonText)
        {
            using (var writer = new StreamWriter(@"parts.json", false, Encoding.UTF8))
            {
                // Jsonファイルとして出力.
                writer.Write(jsonText);
            }
        }
    }
}

メインクラス

最後に、各クラスを呼び出すメインクラスです。

Program.cs

using System;
using System.Collections.Generic;

namespace CsvConverter
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            var reader = new CsvReader();
            var partsList = reader.ReadCsv();

            if (partsList == null)
            {
                return;
            }
            
            var creator = new JsonCreator();
            var sampleMetaParts = new MetaParts
            {
                ModelName = "Model1",
                PartsList = partsList
            };
            var jsonText = creator.Create(sampleMetaParts);
            creator.Output(jsonText);
        }
    }
}

Deveropers.IO 2017 WORLD in 大阪に行ってきました

はじめに

9/23に梅田スカイビルで行われた、クラスメソッド社の方々によるDeveropers.IO 2017 WORLD in 大阪に行ってきました。

dev.classmethod.jp

内容は今年7/1に東京で行われた Deveropers.IO 2017 や、
大阪オフィスの方による計4セッションでした。

聞き漏らしたり間違って理解しているところもあるかとは思いますが、
思うままに書き留めておくことにします。
(各セッションの資料は公開してくれるとのことなので、公開された順にリンクを貼っていく予定です)

クラメソの請求を支える技術(サーバーレス編)

受注から納品後の請求処理までのやり取りをIT化したときの流れ、
見直した後の構成などを紹介する内容でした。

正直一番感じたのは、外から見てイケてる会社であっても、
手動だったりこなれていないところというのは残っているものなのだなぁ、ということでした。

どんな会社でも特に表に出づらい社内のやり取りなど、
どうしても置いてきぼりになりがちだとは思いますが、それをガッと大きく変えていけるところは強いなぁ、と感じました。

あと40代の生存戦略の話で、
例えばWebサービスを作るときにAPIやOAuth2.0などの深い知識と技術を身に着けて活躍する専門家になるのか、
それらの技術をパーツとして組み合わせ、糊付けしてWebサービスを作る人になるのかを決めることが大事。

(意訳)という話も印象的でした。

自分はどうしたいだろう。

何でも完璧にこなすスーパーマンになることができれば良いですが、
それはきっと難しい。

じゃあ何を選ぶのか。どうありたいか。

そんなことを考えさせられたセッションでした。

あとしがないOLさんって女性だったんだ…て

基礎からのOAuth2.0

OAuth2.0の解説、というのが内容の中心ですが、
まずは混同されがちな認証と認可の違いについてのお話から。

よくあるTwitterアカウントを使ってサービスの認証を行う、
というのはOAuthで行うことではない、という話。

これらの内容から、ではOAuth2.0は何をするものなのか、
処理の流れ(アカウントトークンの受け渡しなど)について、
ジョークも交えつつ (いや渋谷の女子高生とか本気かもしれませんが) 噛み砕いて解説されていました。

このセッションについては動画、スライドが公開されているため、
もう一度じっくり見返して理解していきたいところです。
(分かりづらかったのではなく、あまりに私の基礎知識がなさすぎた)

www.slideshare.net

www.youtube.com

クラメソのWebサイトを支える技術

Developers.IOブログなどのWebサイトの構成などを、
その特徴や利点などを交えながら紹介されました。

が、ちょっと私の知識が足りなさすぎて理解が追いつかなかったというのが本音のところです。。。

使用されているAWSのサービスなどについては、資料も見ながら一つずつ辿ってみたいです。

dev.classmethod.jp

Alexaで変わる開発、変わらない開発

Amazonによる、Echoなどのスマートスピーカーを操作することができるAlexaの紹介と、
シンプルな内容でAlexaを動作させるライブ開発、という内容でした。

ステートレスであるAWS Lambdaで、ステートフルな会話から必要なコマンドを拾っていく、
というのは確かに工夫が必要でしょうし、
画面に表示がなく、音声のみによる入力・フィードバックするUIもまだこれから、というところでしょう。

以前Umeda.apk(だったはず)で見たGoogle Homeや今回のAlexaなど、
どれか一つくらいは実際にも触ってみたいところ。

Echoは日本で使えるのはまだ先ですよね。。。

Google Homeは年末くらいに日本でも発売するらしいので、こっちを先に試してみても良さそう。

www.lifehacker.jp

あと開発の様子はGoogle HomeもAlexaも似通っているところがあって、
(揃えているのかもしれませんが)やっぱりこういうやり方が現時点では一番なのかな、とも思いました。

あと何より、ライブ開発、ライブコーディングは見てるだけでも緊張感ありすぎでしたwww

おわりに

楽しかったです。

自分の知識が足りなくて理解が追いつかなかったところも正直ありましたが、
そこはそれ。お話されていた内容をキーワードとして、少しずつ調べていきたいと思います。

やっぱり社内の技術的な内容(だけではないけど)を、
外部にも発信していけるというのは強いなぁ、とも感じました。

クラスメソッドの皆様、ありがとうございました!!

Pythonで CSV -> Json を作る(そしてそれをUnityで読み込み)

はじめに

前回に引き続き必要になったのでメモっておきます。

Pythonを使ってCSVとして保存されたファイルを読み込み、Jsonファイルとして出力。
それをUnityで読み込みます。

Pythonを使うことになった理由は単に興味があったからですw

※2017.9.20修正
Pythonのファイル名、データを格納するための Parts クラスでのアトリビュートの宣言方法を修正しました。

CSVを読み込む

まずはCSVを読み込んで、 Parts というクラス(酷い名前なのは気にしない方向で。。。)に格納します。

parts.csv

PartsNo,PartsName,Description,
No.1,Parts1,一つ目のパーツです,
No.2,Parts2,二つ目のパーツです,

parts.py

 # -*- coding: utf-8 -*-
# coding: utf-8
class Parts:
    def __init__(self, parts_no: str, parts_name: str, description: str):
        self.parts_no = parts_no
        self.parts_name = parts_name
        self.description = description

main.py

 # -*- coding: utf-8 -*-
import csv
from parts import Parts


def main():
  # CSVファイルを読み込む.
  with open(f'parts.csv', encoding='utf-8') as csvFile:
    for index, row in enumerate(csv.reader(csvFile)):
        # タイトル行を無視する.
        if index <= 0:
            continue

        # 読み込んだ内容に[]が含まれているためそれを取り除く.
        replace_row = remove_symbols(str(row))
        split_rows = str.split(replace_row, ',')

        # コンマ区切りでSplitした内容をクラスに格納.
        new_parts = Parts(split_rows[0], split_rows[1], split_rows[2])


def remove_symbols(original: str):
    # 読み込んだ内容に[]、半角スペースが含まれているためそれを取り除く.
    remove_left_bracket = str.replace(original, '[', '')
    remove_right_bracket = str.replace(remove_left_bracket, ']', '')
    remove_space = str.replace(remove_right_bracket, ' ', '')
    return remove_space

main()

  • 「with」を使用することで、C#の「using」と同様ファイルの使用が終わったら自動で開放してくれるようになります。
  • 読み込んだ内容は「[‘PartsNo’, ‘PartsName’, ‘Description’, ‘’]」のように [ と ] が含まれるため、それを取り除く必要があります
    (もう少し上手いやり方がありそうな気はしています)。
  • 今回は読み込んだ内容をわざわざクラスに入れる必要はあまりないのですが、形式や文字数に制限がある場合などはクラス格納 -> チェックとした方が良さそうです。

Jsonファイルとして出力

クラスのデータをDictionaryデータとして受け取る

このままクラスをJsonに変換できると良いのですが(C#Javaのように)、
Pythonでは難しいようです。

そのため、クラスとして格納したデータを受け取って、Dictionaryとして返すようにします。

parts_dictionary_factory.py

 # -*- coding: utf-8 -*-
from parts import Parts


class PartsDictionaryFactory:

    def create(self, target_parts: Parts):
        if type(target_parts) != Parts:
            return

        return {"PartsNo": target_parts.parts_no, "PartsName": target_parts.parts_name,
                "Description": target_parts.description}

main.py

 # -*- coding: utf-8 -*-
import csv
from parts import Parts
from parts_dictionary_factory import PartsDictionaryFactory


def main():
    parts_dictionary = []
    dictionary_creator = PartsDictionaryFactory()

    with open(f'parts.csv', encoding='utf-8') as csvFile:
        for index, row in enumerate(csv.reader(csvFile)):
            if index <= 0:
                continue
            replace_row = remove_brackets(str(row))
            split_rows = str.split(replace_row, ',')
            new_parts = Parts(split_rows[0], split_rows[1], split_rows[2])

            # Dictionaryのデータに変換したものをDictionaryに追加.
            parts_dictionary.append(dictionary_creator.create(new_parts))

~省略~

Jsonファイルの出力

あとはこれまで取得・変換した文字列をJsonに置き換えて、 ファイルとして出力するだけです。

main.py

# -*- coding: utf-8 -*-
import json
import csv
from parts import Parts
from parts_dictionary_factory import PartsDictionaryFactory


def main():
    parts_dictionary = []
    dictionary_creator = PartsDictionaryFactory()

    with open(f'parts.csv', encoding='utf-8') as csvFile:

        for index, row in enumerate(csv.reader(csvFile)):
            if index <= 0:
                continue
            replace_row = remove_symbols(str(row))
            split_rows = str.split(replace_row, ',')
            new_parts = Parts(split_rows[0], split_rows[1], split_rows[2])
            parts_dictionary.append(dictionary_creator.create(new_parts))

    meta_parts = {"ModelName": "Model1", "PartsList": parts_dictionary}

    # 文字列をJson形式に変換.
    json_text = json.dumps(meta_parts)

    # ファイル出力.
    with open(f'parts.json', 'w') as file_object:
        file_object.write(json_text)
        file_object.flush()


def remove_symbols(original: str):
    remove_left_bracket = str.replace(original, '[', '')
    remove_right_bracket = str.replace(remove_left_bracket, ']', '')
    remove_space = str.replace(remove_right_bracket, ' ', '')
    return remove_space


main()

結果として下記のようなファイルが作成されます。

parts.json

{
  "ModelName": "Model1",
  "PartsList": [
    {
      "PartsNo": "'No.1'",
      "PartsName": "'Parts1'",
      "Description": "'\u4e00\u3064\u76ee\u306e\u30d1\u30fc\u30c4\u3067\u3059'"
    },
    {
      "PartsNo": "'No.2'",
      "PartsName": "'Parts2'",
      "Description": "'\u4e8c\u3064\u76ee\u306e\u30d1\u30fc\u30c4\u3067\u3059'"
    }
  ]
}
  • 実際は改行されずに出力されますが、見やすさのために編集しています。

UnityでJsonファイルを読み込む

UnityでJsonのデータをクラスに格納するのは以前もやりましたが、
今回もJsonUtilityを使用します。

まずはJsonのデータを格納するクラスの準備から。

今回はJsonの中に配列(PythonでDictionaryとして出力したもの)が含まれており、
これを格納する Parts というクラスと、
Parts のリスト、及びメタ情報(ModelName)を格納する MetaParts というクラスを作成します。
(名前の酷さはry)

Parts.cs

using System;

[Serializable]
public class Parts
{
    public string PartsNo;
    public string PartsName;
    public string Description;
}

MetaParts.cs

using System;
using System.Collections.Generic;

[Serializable]
public class MetaParts
{
    public string ModelName;
    public List PartsList;
}
  • Jsonのデータを格納するクラスには [Serializable] をつけておく必要があり、
    これがないとうまくデータを格納できませんでした。

ファイルの読み込みとJsonデータからの変換

あとはJsonファイルを読み込み、クラスに格納します。
JsonファイルはUnityEditorで動かす場合は Assets フォルダ直下、Windowsで出力した場合は プロジェクト名_Data フォルダの直下に置きます。

FileLoader.cs

using System.IO;
using System.Text;
using UnityEngine;

public class FileLoader
{
    private readonly string filePath;
    public FileLoader()
    {
        filePath = Application.dataPath + @"/parts.json";
    }
    public MetaParts LoadFromJson()
    {
        if (File.Exists(filePath))
        {
      // ファイルの読み込み.
            using (var reader = new StreamReader(filePath, Encoding.UTF8))
            {
        // ファイルの内容は一括で読み込む.
                var readText = reader.ReadToEnd();
                if (readText.Length > 0)
                {
          // Jsonからの変換に関するエラーチェックは省略.
                    return JsonUtility.FromJson(readText);
                }
            }
        }
        return new MetaParts();
    }
}

あとはこのクラスを読んであげればOKです。

終わりに

Pythonを使うことで、さらっと処理が書けるのは良いと感じます。

ただ、C#でやるように常に型を意識して書きたいのならちょっと厳しいかもしれませんね。

その辺り、Pythonならではの便利なやり方というものがあると思うので、
それを身につけられたらな、と思います。

参照

Python

Unity