ぽにょろん

思いついたこととメモ

c# で default(T) した時の値

default(string) が Null なのをよく忘れるので、 default(T) の値をまとめてみました。

class Program
{
    static void Main(string[] args)
    {
        $@"dyte: {default(byte)}".Dump();  //0
        $@"sbyte: {default(sbyte)}".Dump();  //0 
        $@"int: {default(int)}".Dump();  //0 
        $@"uint: {default(uint)}".Dump();  //0 
        $@"short: {default(short)}".Dump();  //0 
        $@"ushort: {default(ushort)}".Dump();  //0 
        $@"long: {default(long)}".Dump();  //0 
        $@"ulong: {default(ulong)}".Dump();  //0 
        $@"float: {default(float)}".Dump();  //0 
        $@"double: {default(double)}".Dump();  //0 
        $@"char(hex): {Convert.ToInt32(default(char)):X}".Dump();  //0 
        $@"bool: {default(bool)}".Dump();  //false
        $@"object: {default(object) ?? "null"}".Dump();  //null
        $@"string: {default(string) ?? "null"}".Dump();  //null
        $@"decimal: {default(decimal)}".Dump();  //0
        var sample = default(Sample1);
        $@"struct(Prop1): {sample.Prop1 ?? "null"}".Dump();  //null
        $@"struct(Prop2): {sample.Prop2}".Dump();  //0
        $@"Class(isNull): {default(Sample2) == null}".Dump();  //null
        $@"Enum: {default(EnumSample)}".Dump();  //num1
        Console.ReadLine();
    }
}
public enum EnumSample { num1, num2, num3 }
public struct Sample1 { public string Prop1; public int Prop2; }
public class Sample2
{
    public string Prop1 { get; set; }
    private int Prop2 { get; set; }
}
public static class StringExtension
{
    public static void Dump(this string input)
    {
        Console.WriteLine(input);
    }
}

f:id:kowill:20150906110159p:plain

分散トランザクション(MSDTC)の設定をする

基本的に一度しかやらない設定なため、新マシンだと大抵引っかかるので簡単にまとめてみました。
PowerShellでの設定です。

検証環境

Windows10
PSVersion 5

分散トランザクション(MSDTC)とは

簡単には複数のDBにトランザクションを張るみたいなものですかね。
詳しい人の解説を読んでください(笑)

困ったときのMSページ↓
MS DTC 分散トランザクション

分散トランザクション コーディネーター

よく引っかかるあれ

f:id:kowill:20150827124940p:plain

やること

  • ローカルDTCの設定
  • Firewallの設定
  • Serviceの起動

ローカルDTCの設定

Local DTC

Firewallの設定

設定はどちらかで。
なぜか、自分の複数の環境でGet-NetFirewallRuleした時の見え方が違ったので。。

gist9dd5acd041b1f858f7ee

Serviceの起動

このあたりは必要に応じて。

Set-Service MSDTC -StartupType "Automatic"  
  
Start-Service MSDTC

結構、手間取るし辛いだけということになりますよねぇ。

T-SQLでOUTPUT句を使う

OUTPUT句って結構便利だと思っているんですが、そうそう使わないこともあってなかなか覚えられないorz
そんなわけでサンプルを書いてみました。

まずは書き方

何はともあれ、MSDN参照しましょう。

OUTPUT 句 (Transact-SQL)

SQLServer2005から使えるようです。

insert into [table] 
output inserted.* 
values ( 'hoge' ) 

update [table] set [colName] = 'po' 
output deleted.*, inserted.* 
where [colName] = 'aiueo'

delete from [table] 
output deleted.* 
where [colName] = '123456789'

ついでにやりたいことの実験

複数のプロセスから重複なく指定件数だけ更新したい。
かつ更新したレコードが欲しい。

テスト用のテーブルを用意。

create table test(id Integer, kind Integer, memo nvarchar(max), assignedName nvarchar(max));
--delete test;

declare @idx int;
set @idx = 0;

while @idx < 10000
begin
  insert test values(@idx, @idx % 3, 'hoge', Null);
  set @idx = @idx + 1;
end;

サンプルコードを用意。
理解が怪しいところがあるので、大丈夫だろうか。(; ̄ー ̄A

//using Dapper;

static void Main(string[] args)
{
   var list = new SynchronizedCollection<Test>();
   ThreadPool.SetMinThreads(200, 200);
   Parallel.ForEach(
       Enumerable.Range(0, 300),
       new ParallelOptions { MaxDegreeOfParallelism = 200 },
       num =>
       {
           Console.WriteLine(string.Format("BEGIN:{0}", num));
           var data = GetData(0, num.ToString()).Result;
           foreach (var item in data)
           {
               list.Add(item);
               Console.WriteLine(string.Format("Num:{0}, Id:{1}", num, item.Id));
           }
           Console.WriteLine(string.Format("END:{0}", num));
        });
    Console.ReadLine();
}
public async static Task<IEnumerable<Test>> GetData(int kind, string name)
{
    var str = @"接続文字列";
    using (var con = new SqlConnection(str))
    {
        con.Open();
        using (var tran = con.BeginTransaction())
        {
            var result = await con.QueryAsync<Test>("Update Top (10) test set assignedName = @Name output inserted.id, inserted.Kind where (kind = @Kind) and (assignedName IS NULL)", new { Kind = kind, Name = name }, tran);
            tran.Commit();
            return result;
        }
    }
}
public class Test
{
    public int Id { get; set; }
    public int Kind { get; set; }
    public string Memo { get; set; }
    public string AssignedName { get; set; }
}

実行結果

今のところ大体思った通り動いてる。

f:id:kowill:20150811224721p:plain

権限昇格したプログラムからネットワークドライブが参照できない

UACが導入されて以降、権限昇格したプログラムからネットワークドライブが参照できなくて困ったことが何度かあります。
マシンを入れ替えるたびにあれ、なんだっけとなっていたのでメモとして残しておきます。

そもそも

Some Programs Cannot Access Network Locations When UAC Is Enabled

Linkを読むのが早いですが、簡単には以下のようです。
* ユーザーのトークンに「フィルタ済みトークン」と「フルトークン」なるものがある。
* 通常は「フィルタ済みトークン」が使われているので、ネットワーク共有のマッピングもこちらに割り当てられている。
* UACで権限昇格した際には「フルトークン」がアプリに渡される。
* 「フルトークン」にはネットワーク共有のマッピングが割り当たっていない。

こんな理由で、ネットワークドライブが見えないといったことが起こるようです。
(参考)

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
var principal = (WindowsPrincipal)Thread.CurrentPrincipal;

principalの中身を見れば、違いが分かります。

解決法

レジストリをいじってあげればよさそうです。
上記、Linkにも書いてある通りです。

EnableLinkedConnections

要再起動。

再現

  1. 通常に起動した状態。ネットワークドライブが見える。
    f:id:kowill:20150805075359p:plain

  2. 管理者実行した状態。ネットワークドライブ見えない。
    f:id:kowill:20150805075402p:plain

  3. EnableLinkedConnectionsを1にして、管理者実行。
    見える、見えるぞ! f:id:kowill:20150805075404p:plain

Dismで.NET Framwork3.5(2.0/3.0)をインストールする

ちょっと試す機会があったので、やってみました。
Windows8やWindows10では、.NET Framwork3.5以前は無効の状態が初期状態なので、必要に応じて有効にする必要があります。
普通にDismでコマンド投げてあげればよさそうです。

.NET Framwork3.5のインストール

LimitAccessをつけないとダメというのも見聞きしたのですが、私の環境だとオンライン状態であれば特に問題なさそうでした。
Sourceを指定してあげるのが、一番確実ですかね。

ところで、Get-FeatureInfoで取得できる再起動が必要かどうかの情報があるんですが、
f:id:kowill:20150804235348p:plain
Possibleってなかなか面白いですね(笑)