rksoftware

Visual Studio とか C# とかが好きです

異なる型のオブジェクトに同じ名前のプロパティの値を全てセットする その2

大量のプロパティを持つオブジェクト間でプロパティの値をコピーしたいことがあります。
毎回コピーするコードを書くのも面倒なので、メモをしておきます。
昨日のコードは型が異なる場合に使えなかったので、雑に型変換処理を入れてみました。
下記コードの PropertyCopier クラスの CopyTo メソッドでコピーできます。

public static class PropertyCopier
{
    public static T CopyTo<T>(object src, T dest)
    {
        var it = typeof(int);
        if (src == null || dest == null) return dest;
        var srcProperties = src.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite);
        var destProperties = dest.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite);
        var properties = srcProperties.Join(destProperties, p => p.Name, p => p.Name, (p1, p2) => new { p1, p2 });
        foreach (var property in properties)
        {
            if (property.p1.PropertyType == property.p2.PropertyType)
            {
                property.p2.SetValue(dest, property.p1.GetValue(src));
            }
            else
            {
                var f =
                (property.p2.PropertyType == typeof(string)) ? v => Convert.ToString(v)
                    : (property.p2.PropertyType == typeof(short)) ? v => Convert.ToInt16(v)
                    : (property.p2.PropertyType == typeof(short?)) ? v => Convert.ToInt16(v)
                    : (property.p2.PropertyType == typeof(bool)) ? v => Convert.ToBoolean(v)
                    : (property.p2.PropertyType == typeof(bool?)) ? v => Convert.ToBoolean(v)
                    : (property.p2.PropertyType == typeof(int)) ? v => Convert.ToInt32(v)
                    : (property.p2.PropertyType == typeof(int?)) ? v => Convert.ToInt32(v)
                    : (property.p2.PropertyType == typeof(long)) ? v => Convert.ToInt64(v)
                    : (property.p2.PropertyType == typeof(long?)) ? v => Convert.ToInt64(v)
                    : (property.p2.PropertyType == typeof(double)) ? v => Convert.ToDouble(v)
                    : (property.p2.PropertyType == typeof(double?)) ? v => Convert.ToDouble(v)
                    : (property.p2.PropertyType == typeof(decimal)) ? v => Convert.ToDecimal(v)
                    : (property.p2.PropertyType == typeof(decimal?)) ? v => Convert.ToDecimal(v)
                    : (property.p2.PropertyType == typeof(DateTime)) ? v => Convert.ToDateTime(v)
                    : (property.p2.PropertyType == typeof(DateTime?)) ? v => Convert.ToDateTime(v)
                    : (Func<object, object>)null;
                try { property.p2.SetValue(dest, f?.Invoke(property.p1.GetValue(src))); } catch { property.p2.SetValue(dest, null); }
            }
        }
        return dest;
    }
}


class Program
{
    static void Main(string[] args)
    {
        var dest = PropertyCopier.CopyTo(new Test1() { Prop1 = "p1", Prop2 = "p2", Prop3 = "p3" }, new Test2());
        Console.WriteLine($"{dest.Prop1}, {dest.Prop2}, {dest.Prop3}");

        Console.ReadKey();
    }
}

public class Test1
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
}

public class Test2
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
}

異なる型のオブジェクトに同じ名前のプロパティの値を全てセットする

大量のプロパティを持つオブジェクト間でプロパティの値をコピーしたいことがあります。
毎回コピーするコードを書くのも面倒なので、メモをしておきます。
下記コードの PropertyCopier クラスの CopyTo メソッドでコピーできます。

public static class PropertyCopier
{
    public static T CopyTo<T>(object src, T dest)
    {
        if (src == null || dest == null) return dest;
        var srcProperties = src.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite);
        var destProperties = dest.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite);
        var properties = srcProperties.Join(destProperties, p => new { p.Name,p.PropertyType}, p => new { p.Name, p.PropertyType }, (p1, p2) => new { p1, p2 });
        foreach (var property in properties)
            property.p2.SetValue(dest, property.p1.GetValue(src));
        return dest;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var dest = PropertyCopier.CopyTo(new Test1() { Prop1 = "p1", Prop2 = "p2", Prop3 = "p3" }, new Test2());
        Console.WriteLine($"{dest.Prop1}, {dest.Prop2}, {dest.Prop3}");

        Console.ReadKey();
    }
}

public class Test1
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
}

public class Test2
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
}

C# 7.1 の使い方

Visual Studio 2017 Version 15.3.0 がリリースされました。
このリリースで C# 7.1 が使えるようになったので試してみます。

■ アップデート

Visual Studio のアップデートは ツール > 拡張機能と更新プログラム から行えます。

■ C# 7.1 の使い方

プロジェクトを新規作成しただけでは C# 7.0 しか使えません。C# 7.1 を使うには設定を行う必要があります。
1. プロジェクトのプロパティ > ビルド
2. ページの右下の [詳細設定]
3. [ビルドの詳細設定] ダイアログの 全般 > 言語バージョン
 [C# の最新のマイナーバージョン (最新)]
 または
 [C# 7.1]
 に設定。

■ 推定タプル名の使い方

C# 7.1 の新機能の一つ 推定タプル名 を使うには nugetSystem.ValueTuple をインストールする必要があります。

■ C# 7.1 の新機能

・非同期 Main メソッド

https://github.com/dotnet/csharplang/blob/master/proposals/async-main.md
Main メソッドを async にできます。

static async Task Main(string[] args)
{
    var text = await new System.Net.Http.HttpClient().GetStringAsync("http://rksoftware.hatenablog.com/");

    Console.WriteLine(new string(text.Take(200).ToArray()));
    Console.ReadKey();
}

・ジェネリックによるパターン マッチング

https://github.com/dotnet/csharplang/blob/master/proposals/generics-pattern-match.md
ジェネリック型の引数に対してのパターンマッチングが可能になりました。これまでは、下記の例では、Match<T> メソッドの引数 a に対するパターンマッチングはコンパイルエラーでした。

static void Main(string[] args)
{
    Console.WriteLine(Match("test"));   // string

    Console.ReadKey();
}

static string Match<T>(T a)
{
    switch (a)
    {
        case int v:
            return "int";
        case string v:
            return "string";
        default:
            return "default";
    }
}

・“既定” リテラル

https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-default.md
型を推論できる個所では、規定値を設定する際の default(型名) の型名を省略できるようになりました。

static void Main(string[] args)
{
    // これまでは default(int) の様に型の指定が必要だった
    int i = default;
    Console.WriteLine(i);

    Console.WriteLine(D());

    Func<string> l = () => (string)default;
    Console.WriteLine(l() == null);

    string s = default;
    Console.WriteLine(s ?? default);
    Console.WriteLine(s == null? default:s);

    Console.ReadKey();
}

static DateTime D()
{
    return default;
}

・推定タプル名

https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/infer-tuple-names.md
タプルの使用時に、要素の名前が推定で付けられるようになりました。推定できない場合(一つの変数が複数回使われた場合など)はこれまで通り、ItemX という名前になります。

static void Main(string[] args)
{
    var pv = new System.Collections.Generic.KeyValuePair<int, int>(1, 2);
    var t1 = (pv.Value, pv.Key);
    
    // これまでは t.Item1 や t.Item2 となっていた
    Console.WriteLine(t1.Key);
    Console.WriteLine(t1.Value);

    int x = 3, y = 4;
    var t2 = (x, y);
    
    Console.WriteLine(t2.x);
    Console.WriteLine(t2.y);

    Console.ReadKey();
}

 
C# 7.1 はマイナーバージョンアップだけあって新機能は少ないですが、よりコードを書きやすくしてくれそうですぐに使いたいですね。

城東.NET #11 勉強会で話をしてきました

先日開催した

にて Bait and Switch を試してみた というタイトルで話をしました。

便利に使っているものの実際にどうなっているのかは確認していなかった Bait and Switch を試して確認してみました。

■ 次回予定

来月は 09月20日(水)に開催の予定です。

.NET に関心のある方、是非遊びに来てください。

.NET 読書会を開催しました。(2017/08 3週)

■ .NET 読書会

 .NET 読書会「プログラミング Xamarin 上」読書会を開催しました。

 本会は毎週木曜日に開催して行く予定です。
 今のところは読書と質問相談実践ということで始めました。いずれ LT などを積極的に行える場に育てて行けたらと思っています。

■ 初心者歓迎

 毎回簡単な概要のまとめを発表形式で共有するので、初心者の方でも安心な会(にして行くつもり)です。
 書籍だけ握りしめて遊びに来てください。

■ 今期の書籍

 今期の書籍は「プログラミング Xamarin 上」です。

 読書会は、というか技術系の会は最初から参加していないと途中からは参加しずらいということはありません。
 興味がありましたら、書籍だけ握りしめて気軽に遊でに来てください。

■ 次回予定

 来月は 08月24日(木)に開催の予定です。

城東.NET #11 勉強会を開催しました。

■ 城東.NET

 城東.NET #11 を開催しました。

 城東.NET は東京の最近は秋葉原で毎月第3水曜日に開催している .NET 系の勉強会です。
 発表を中心として、発表でなくとも最近やった事や新しい情報などを参加者で共有している会です。

 今月の内容も、上記イベントサイトに資料やコメントが載っているものもあります。
 興味があったら覗いてみてください。

■ 次回予定

 来月は 09月20日(水)に開催の予定です。

 .NET に関心のある方、是非遊びに来てください。

Visual Studio 2017 Version 15.3.0 がリリースされました。

Visual Studio 2017 Version 15.3.0 がリリースされました。
ので早速アップデートしてみました。

■ アップデート

アップデートは ツール > 拡張機能と更新プログラム から行えます。
私の環境では、90分以上の時間がかかりました。

■ リリースノート

日本語のリリースノートはこちら

■ C# 7.1

新機能はいくつもありますがその中で一番気になるのが、C# 7.1 言語サポートです。

非同期 Main メソッドジェネリックによるパターン マッチング“既定” リテラル推定タプル名が使えるようになりました。

■ .NET Standard 2.0

同時に使えるようになった .NET Standard 2.0 も気になりますが、今日のところはリンクだけ。
 
C# 7.1 はマイナーバージョンアップだけあって新機能は少ないですが、よりコードを書きやすくしてくれそうですぐに使いたいですね。