PG日誌

読者です 読者をやめる 読者になる 読者になる

PG日誌

主にc#の事を書いています

VisualStudio2013へ.NET Framework4.6.2を導入する

Tool

f:id:Takachan:20170114224940j:plain

だいぶ前に、VisualStudio2013へ.NET4.6.1の導入の仕方を書きましたが、.NET4.6.2がリリースされたので導入の手順を書きたいと思います。



【旧記事】.NET4.6.1の導入の仕方

前に書いた記事です。

takachan.hatenablog.com


概要

.NET4.6.2が2016年8月にリリースされました。今は、.NET4.6でも.NET4.6.1ともにサポート期間内で特に問題ないみたいです。ただ、まぁ、、、いつも通りある程度時間がたつと、古いバージョンが徐々に切り捨てられていく事になると思われるため、新規に開発する際はより新しいバージョンを使用したほうがよいかと思います。


サポートライフサイクルについて

SIer脳では大変重要なサポート期間の確認です。

Microsoft .NET Framework サポート ライフサイクル ポリシー

Note:

2017年1月の時点で、.NET4.6, .NET4.6.1のサポートは継続中です。.NET4.6.2は記述見当たらないですね。


現在の状態

導入前に現在の状態を確認します。VSを立ち上げてソリューションもしくはプロジェクト作成画面で選択可能な.NETのバージョンを確認します。

f:id:Takachan:20170115162810p:plain

前回導入した4.6.1までしか表示されていません。


導入方法

MSのサイトから開発者キットをダウンロード

.NET Framework 4.6.2 Developer Pack リンク切れの場合「.NET Framework 4.6.2 Developer Pack」で検索お願いします。

そこから2つexeをダウンロードし実行します。 安全のためインストーラを起動する前にVisualStudioは閉じておきましょう。

f:id:Takachan:20170115164025p:plain

両方とも選択します。

f:id:Takachan:20170115164103p:plain

ダウンロードできたら、「NDP462-DevPack-KB3151934-ENU.exe」→「
NDP462-DevPack-KB3151934-JPN.exe」の順にインストールしていきます。


VisualStudioの再起動

VSが起動したらプロジェクト作成画面を確認します。

f:id:Takachan:20170115164945p:plain

特に問題なく利用可能になっています。


最後に

ライフサイクルサポートページに4.6.2の記述がないわ、Windows10は相変わらず普及しないわ、なんだか環境は超微妙ですね。.NET Coreはオープンソース化したりVisualstudio2015は大変出来が良いのでMSの担当チームごとに温度差を感じています。

c#でJsonをシリアライズ、デシリアライズする

c#

f:id:Takachan:20170115150341j:plain

c#Jsonデータをシリアライズシリアライズする方法のメモです。.NET Frameworkの標準ライブラリにあるDataContractJsonSerializerを使ってファイルやネットワークから読みとったJson文字列をC#のオブジェクトへ変換したり、オブジェクトの内容をJson文字列へ変換を行います。

Json.NETは使用しません。

データ構造

今回シリアライズ、デシリアライズするデータとクラスの構成は以下の通りです。

クラス構成

c#のクラスの内容です。

using System.Runtime.Serialization.Json;

[DataContract]
public class Person
{
    [DataMember]
    public int ID { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public IDictionary<string, string> Attributes { get; private set; }

    public Person()
    {
        this.Attributes = new Dictionary<string, string>();
    }
}

扱うJsonデータ

クラスをシリアライズした時、もしくはデシリアライズするときに使用するデータは以下となります。

[
    {
        "ID": 0, 
        "Name": "Taka", 
        "Attribute": {
            "key1": "value1"
            "key2": "value2"
            "key3": "value3"
        }
    }, 
    {
        "ID": 1, 
        "Name": "PG", 
        "Attribute": {
            "keyAA": "valueAA"
            "keyBB": "valueBB"
            "keyCC": "valueCC"
        }
    }
]

準備

先ずはプロジェクトとコードに以下準備を行います。

(1) DataContractJsonSerializerを使用するにプロジェクトにSystem.Runtime.Serializationの参照を追加します。

(2) 使用するコードに以下using宣言を追加します。

using System.Runtime.Serialization;

(3) シリアル化対象のクラスに以下属性を指定します。

[DataContract]
public class Person

(4) 対象メンバーに以下属性を指定します。

[DataMember]
public int ID { get; set; }

補足

もしクラスとJsonでフィールドの名前が違う場合、属性にNameが指定できます。

クラス名と異なる場合

[DataContract(Name = "Taka")]
public class Person

メンバー名が異なる場合

[DataMember(Name = "key")]
public int ID { get; set; }

Note:

クラスとJsonでフィールドの名前が違う場合、属性にNameが指定できます。

リアライズ

DataContractJsonSerializerとMemoryStreamを使ってオブジェクトをJsonシリアライズします。

public static class JsonUtility
{
    /// <summary>
    /// 任意のオブジェクトをJsonメッセージへシリアライズします。
    /// </summary>
    public static string Serialize(object graph)
    {
        using (var stream = new MemoryStream())
        {
            var serializer = new DataContractJsonSerializer(graph.GetType());
            serializer.WriteObject(stream, graph);
            return Encoding.UTF8.GetString(stream.ToArray());
        }
    }
}

使い方

使い方はこんな感じです。

static void Main(string[] args)
{
    // データの作成
    var p_1 = new Person()
    {
        ID = 0,
        Name = "Taka",
    };
    p_1.Attributes.Add("key1", "value1");
    p_1.Attributes.Add("key2", "value2");
    p_1.Attributes.Add("key3", "value3");

    var p_2 = new Person()
    {
        ID = 1,
        Name = "PG",
    };
    p_2.Attributes.Add("keyAA", "valueAA");
    p_2.Attributes.Add("keyBB", "valueBB");
    p_2.Attributes.Add("keyCC", "valueCC");

    // リストに設定する
    List<Person> pList=new List<Person>() { p_1, p_2 };

    // リストをデシリアライズ
    string json = JsonUtility.Serialize(pList);

    // 内容をコンソールへ表示
    Console.WriteLine(json);
}

これで冒頭のJsonの例と同じ値が出力されます。

シリアライズ

今度はデシリアライズです。

public static class JsonUtility
{
    /// <summary>
    /// Jsonメッセージをオブジェクトへデシリアライズします。
    /// </summary>
    public static T Deserialize<T>(string message)
    {
        using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(message)))
        {
            //var setting = new DataContractJsonSerializerSettings()
            //{
            //    UseSimpleDictionaryFormat = true,
            //};
            var serializer = new DataContractJsonSerializer(typeof(T), /*setting*/);
            return (T)serializer.ReadObject(stream);
        }
    }
}

使い方

先ほどの例でシリアライズしたメッセージがjsonに入っている状態から以下のようにデシリアライズします。

static void Main(string[] args)
{
    // ...前略...

    // デシリアライズ
    var pDeserializeList = JsonUtility.Deserialize<IList<Person>>(json);

    // 内容の出力
    foreach (var p in pDeserializeList)
    {
        Console.WriteLine("ID = " + p.ID);
        Console.WriteLine("Name = " + p.Name);
        foreach (var att in p.Attributes)
        {
            Console.WriteLine(att.Key + " = " + att.Value);
        }
    }
}

DataContractJsonSerializerSettingsについて

DataContractJsonSerializerSettingsのUseSimpleDictionaryFormatは指定方法によってDictionaryのデータ形式の取り扱い方法が若干変わります。それぞれ動作を確認した結果は以下に載せておきます。

UseSimpleDictionaryFormat = trueの場合

trueの場合、任意のキーと任意のValueがDictionaryの値になります。

[
    {
        "ID": 0,
        "Name": "Taka",
        "Attributes": {
            "key1": "value1",
            "key2": "value2",
            "key3": "value3"
        }
    },
    {
        "ID": 1,
        "Name": "PG",
        "Attributes": {
            "keyAA": "valueAA",
            "keyBB": "valueBB",
            "keyCC": "valueCC"
        }
    }
]

UseSimpleDictionaryFormat = falseの場合

false(もしくは設定しない)の場合、Key="", Value=""のペアの繰り返しの配列扱いになります。多分こっちはあんまり使わないのですが、状況によってどうするか変わると思います。

[
    {
        "ID": 0,
        "Name": "Taka",
        "Attributes": [
            {
                "Key": "key1", 
                "Value": "value1"
            }, 
            {
                "Key": "key2", 
                "Value": "value2"
            }, 
            {
                "Key": "key3", 
                "Value": "value3"
            }
        ]
    },
    {
        "ID": 1, 
        "Name": "PG",
        "Attributes": [
            {
                "Key": "keyAA", 
                "Value": "valueAA"
            },
            {
                "Key": "keyBB", 
                "Value": "valueBB"
            },
            {
                "Key": "keyCC", 
                "Value": "valueCC"
            }
        ],
    }
]

コード全体

上記コード全体をGistにアップアップしました。 良かったら見てください。

JsonUtility.cs · GitHub

VisualStudio2015が使うIEバージョンの変更

Tool

f:id:Takachan:20170115150341j:plain

VisualStudio2015ってデフォルトだとIE9になっています。このままだとネットワークがIEの古いバージョンを制限していたりするとVisualStudio上からログインダイアログすら表示できないのでブラウザがIE11を使用するように変更したいと思います。

Note:

基本的に最近のVisualStudioなら同じ設定で変更できるのでバージョンが違う人が読み替えでOK



変更方法

レジストリを変更することになるので、設定を変更する際の一般的な注意事項は確認してください。

VisualStudio2015を立ち上げる

まず始めにVisualStudio2015を起動します。

Note:

起動時(起動後)にこれから変更したい箇所のレジストリが書き換わってしまうのであらかじめ起動しておきます。順番大事


VisualStudio上でWebブラウザを表示してこのサイトでバージョンを確認します。

f:id:Takachan:20170115151052p:plain

見事に「IE9」と表示されていますね。


レジストリの変更

[Win]キーを押して「regedit」と入力してからエンターを入力します。レジストリエディタが立ち上がるのでエディタのツリーから以下箇所へ移動します。

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION


右側に「devenv.exe」という欄があり値gあ0x0000270f(9999)になっていると思います。この欄をダブルクリックして値を変更します。


だいたい以下のような意味なので入力欄にIE11の値を設定します。

値 (16進数) バージョンと意味
0x2AF8 Internet Explorer 11
0x2711 Internet Explorer 10
0x270F Internet Explorer 9


16進数の先頭の「0x」は入れないでください。

f:id:Takachan:20170115151727p:plain

これで[OK]して先ほど起動したVisualStudioに戻ります。


変更の確認

無事変更できました。(この画面一度表示しちゃうとIE9のままになるので表示したい場合レジストリ変更してから初回表示させてください)

f:id:Takachan:20170115152405p:plain


最後に

この設定ですが、毎回立ち上げるたびにリセットされちゃうので起動するたびに設定の変更が必要です。大変めんどくさいので設定をエクスポートしておいた方がよさそうです。

Visual Studuo Codeのキーショートカット

Tool

f:id:Takachan:20170114224025j:plain

Windows版のVisual Studio Codeのキーショートカットの個人的なメモです。

操作 ショートカット
右端で折り返す Alt + z
MardDownのプレビュー表示 Ctrl + Shift + v

Note:

k-measn法のビジュアル化

c# WPF 作ってみた

クラスタリングで定番のk-means, k-平均法c#WPFをつかって視覚化してみました。

今回は、以下2つのサイトに刺激を受けて作成しています。

play.google.com

tech.nitoyon.com

このアルゴリズムですがはだいたい以下のような手順で進みます。

  1. データを座標へ配置
  2. クラスタをN個配置
  3. データをいちばん近いクラスタに割り当て
  4. クラスタをデータの重心に移動

4で変化がなくなるまで3→4を繰り返します。

実際の動作

早速ですが、作成したアプリの動作です。

初期条件としてクラスタ数5、データ200を与えています。

f:id:Takachan:20170105233735p:plain:h300

[Step]押下1回目、適当に分類された点とクラスタを線で結ぶ。

f:id:Takachan:20170105233829p:plain:h300

[Step]押下2回目、点を一番近いクラスタに再分類

f:id:Takachan:20170105233912p:plain:h300

[Step]押下3回目、クラスタを中心に移動

f:id:Takachan:20170105233959p:plain:h300

[Step]押下4回目、点を最寄りのクラスタに再分類

f:id:Takachan:20170105234031p:plain:h300

のようになり、以降[Step]ボタンを押すと2~4を繰り返します。

開発環境

このアプリの作成環境ですが

で、ソフトの見た目をモダンアプリ風にするためにMahAppsを使用しました。

ソフト構成

気の利いた描画ライブラリはよく知らないため基盤も自分で実装します。

以下画像の通りキャンバス上に、WPFのコントロールクラスタはRectangle、データはEllipse、それらをつなぐ線をLineで描画しています。

f:id:Takachan:20170105235102p:plain:h300

色は、6色をXAML上にあらかじめ記述してコード上からオブジェクトを配置するときにSytpeをFindResourceしています。

成果物について

作ったソフトの見た目はこんな感じです。

f:id:Takachan:20170105224848p:plain:h300

成果物をGitHubに上げています。

github.com

■記号がクラスタでキャプチャーでは3つになっています。 〇がデータで初期状態だと適当に色分けされています。

各数値やウインドウサイズを変更したときは[Reset]で初期化

[Step]ボタン押下で以下動作を(A)→(B)を繰り返します。

コードの説明

クラスタ、点を表す構造体は以下のようにPointModelクラスで行います。見た通りですが、所属グループと座標を持ちます。IDはアニメーション時に必要かと思い実装しましたが現時点では未使用です。

public class PointModel
{
    // クラスタ/点のユニークなID
    public int ID { get; set; }

    // クラスタ/点がどのグループに所属するか
    public int Group { get; set; }

    // 現在の座標
    public double X { get; set; }
    public double Y { get; set; }
}

計算はKmeasnModelクラスで行います。 クラスタと点をリストで管理しています。

public class KmeasnModel
{
    // ...(前略)...

    // クラスタを管理するリスト
    public IList<PointModel> ClusterList { get; private set; }
    // 点を管理するリスト
    public IList<PointModel> MeasurementPointList { get; private set; }

KmeasnModelに初期状態を作るときは、クラスタは中心のほうに寄せて出現するように調整しています。

    public void InitCluster(int max)
    {
        // Calc fixed values in advance
        double xCenter = this.Width / 2;
        double yCenter = this.Height / 2;
        double xRadius = this.Width / 10;
        double yRadius = this.Height / 10;

        this.ClusterList.Clear();
        for (int i = 0; i < max; i++)
        {
            this.ClusterList.Add(new PointModel()
            {
                ID = i,
                Group = i,
                X = this.r.Next((int)(xCenter - xRadius), 
                                (int)(xCenter + xRadius)),

                Y = this.r.Next((int)(yCenter - yRadius), 
                                (int)(yCenter + yRadius)),
            });
        }
    }

同クラス内に点の所属を一番近いクラスタに点の所属を変更するメソッドがあり以下の実装をしています。

    // 一番近いクラスタに点の所属を変更する
    public void ChangeMeasurementPointBelongs()
    {
        foreach (var meas in this.MeasurementPointList)
        {
            PointModel nereCluster = null;
            double nearNolm = double.MaxValue;

            foreach (var cluster in this.ClusterList)
            {
                double x = meas.X - cluster.X;
                double y = meas.Y - cluster.Y;
                double norm = Math.Sqrt(x * x + y * y);

                if (nearNolm > norm)
                {
                    nearNolm = norm;
                    nereCluster = cluster;
                }
            }
            meas.Group = nereCluster.Group;
        }
    }

点の所属が変わった後に呼び出すクラスタの移動です。クラスタに関係する点から重心を取り、クラスタを移動させています。

    // クラスタの移動
    public void MoveCluster()
    {
        foreach (var c in this.ClusterList)
        {
            Point p = this.GetCentroid(c.Group);
            if (double.IsNaN(p.X) || double.IsNaN(p.Y))
            {
                return; // not move
            }
            c.X = p.X;
            c.Y = p.Y;
        }
    }

    // 指定したGroupの重心の取得
    public Point GetCentroid(int group)
    {
        double x = 0;
        double y = 0;
        int cnt = 0;

        var items = this.GetSamples(group);

        foreach (var item in items)
        {
            cnt++;
            x += item.X;
            y += item.Y;
        }
        return new Point(x / cnt, y / cnt);
    }

わかったこと

最後に制作を通じて分かった事ですが

  • Canvasが重い!

    • オブジェクトが2000点程度でもう計算が0.5秒、描画が3秒程かかっています
      • オブジェクトが増えると指数関数的に動作が重くなる!
      • 全部削除 → 新規に追加しているせいかもしれません
  • doubleのNANは==では比較できない

    • double.IsNaN(value)を使わないとNaNかどうかわからない
      • 計算後の値がNaNになる場合の除外ができずクラスタが左上に消えた

でした。

広告を非表示にする