2011年7月13日水曜日

IStructuralEquatableの使い方

IStructuralEquatableについて今までいまいちわからずにいました。ググって出てきたページを読んでいたら使い方が微妙で違和感を覚えたためじっくり調べてみました。そうしたらもうちょっと使いやすいものだということがわかりました。
StructuralComparisons.StructuralEqualityComparerはオブジェクトそのものではなく、その要素を比較するIEqualityComparerを提供します。これを使ってIEqualityComparer<T>の実装例を書いてみました。

public class StructuralEqualityComparer<T> : IEqualityComparer<T> where T: IStructuralEquatable { public bool Equals(T x, T y) { return StructuralComparisons.StructuralEqualityComparer.Equals(x, y); } public int GetHashCode(T obj) { return StructuralComparisons.StructuralEqualityComparer.GetHashCode(obj); } }
こう書いてしまえばどう使うのかわかりやすいでしょうか。このサンプルそのものは new StructuralEqualityComparer<int[]>() のように使えます。
なんでこんなクラスをわざわざ作るのかというと、LINQで要求される比較演算子はどれもIEqualityComparerでなくIEqualityComparer<T>だからです。

2011年2月1日火曜日

TransactionScope classの使い方

.NET Frameworkでtransactionを扱うにはTransactionScope classを使いますが、嵌りやすいのでメモっておきます。

class説明にはisolation levelについて記載されていませんが、デフォルトではSerializableになっています。例えばSQL ServerのデフォルトはReadCommittedなので勘違いしてしまいそうです。では、isolation levelを指定しようとすると、constructorにもpropertyにもそれらしいものがありません。実はpublic TransactionScope( TransactionScopeOption scopeOption, TransactionOptions transactionOptions )のTransactionOption classで指定することになります。 しかし今度は余計なparameterまで渡す必要があります。

  • TransactionScopeOption…これはRequiredがデフォルトです。
  • TransactionOptionsのIsolationLevel…これは指定したかったReadCommittedにします。
  • TransactionOptionsのTimeout…これは指定しないと初期化されず0になってしまい、timeoutなしになってしまいます。デフォルトの値にするためにはTransactionManager.DefaultTimeoutを指定します。
結局、
using( var transaction = new TransactionScope( TransactionScopeOption.Required, new TransactionOptions{ IsolationLevel = IsolationLevel.ReadCommitted, Timeout = TransactionManager.DefaultTimeout, } ) ){ ...; transaction.Complete(); }
とやることになるでしょう。

2010年12月29日水曜日

IsDuplicated拡張メソッド

気が向いたので何となく書いてみました。

public static class Enumerable { public bool IsDuplicated<TSource>( this IEnumerable<TSource> source ) { var keys = new HashSet<TSource>(); return !source.All( keys.Add ); } public bool IsDuplicated<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector ) { var keys = new HashSet<TKey>(); return !source.Select( keySelector ).All( keys.Add ); } }
IsDuplicated() つまり重複があるかどうかを判断する拡張メソッドです。
巷にはDistinct()を使ったりして項目数を数えている方法もありますが、数えるということはIEnumerableを最後まで確認する必要があります。

しかし、重複があるかどうか知りたいだけ、同じものが1ヶ所でもダブっていればそれが知りたい、そんなときに最後まで確認するのは無駄です。IsUnique()でなくIsDuplicated()というメソッド名にしたのもそのためです。どうせダブってるんでしょ? ダブってるなら早く教えてよ、と。

仕組みは簡単。HashSetを使います。HashSet.Add()メソッドは戻り値として重複の有無を教えてくれるのでそれを使います。
更にAll()拡張メソッドは1つでもfalseを見つけると即座に中断して返ってきます。

2010年2月14日日曜日

Dojo基礎文法最速マスター ~CSS編~

Dojoにはテーマがあります。

<style type="text/css"> @import "http://ajax.googleapis.com/ajax/libs/dojo/1.4/dojo/resources/dojo.css"; @import "http://ajax.googleapis.com/ajax/libs/dojo/1.4/dijit/themes/soria/soria.css"; @import "http://ajax.googleapis.com/ajax/libs/dojo/1.4/dijit/themes/nihilo/nihilo.css"; @import "http://ajax.googleapis.com/ajax/libs/dojo/1.4/dijit/themes/tundra/tundra.css"; </style>
最初の1つはいわゆるリセットCSS。残りの3つがテーマ。読み込んだだけでは適用されません。 テーマを適用したい範囲にclass="テーマ名"の属性を付けます。全体に適用したいなら、
<body class="soria">
こんな感じで<body>タグに設定します。
Dojoは読み込まれると<html>タグに次のクラスを設定します。
  • dj_ie / dj_ie6 / dj_ie7 / dj_ie8 / dj_iequirks
  • dj_gecko / dj_ff2 / dj_ff3
  • dj_khtml / dj_safari / dj_chrome
  • dj_opera
  • dj_contentBox / dj_borderBox
このため、ブラウザごとに挙動が違う場合もCSSで簡単に解決できます。 たとえば、IEだけ異なる挙動をする場合、
<style type="text/css"> /* ブラウザ共通 */ .someClass { ...; } /* IEのみ異なる部分を上書き */ .dj_ie .someClass { ...; } </style>
こうすると、CSSの優先順位により!importantしなくてもIEでのみ上書きされます。 CSSだけで解決できるので、JavaScriptで書き換えとかしなくて済みます。

Dojo基礎文法最速マスター ~HTML編~

Dojoにはdojo.parserという機能があり、これがhtmlを編集してくれます。ページ読み込み時にdojo.parserを動作させるには

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.4/dojo/dojo.xd.js" djconfig="parseOnLoad: true"> </script>
と読み込み時に設定するだけ。

dojo.parserはdojotype属性に反応します。
<input dojotype="dijit.form.TextBox" jsid="textbox1" type="text" name="textbox" value="てきすと" />
これで、このtextboxにはdojoの追加機能が付与されます。dojoにはこのinputに対応するJavaScriptオブジェクトがあるわけですがjsid="textbox1"と指定されていた場合、JavaScriptのtextbox1という変数に割り当てられます。
よくdocument.getElementById()で毎回検索しているコードを見かけますが、変数に割り当てられているので必要な時はいつでも簡単にアクセスできます。

dojo.parserは入れ子にも対応していて
<form dojotype="dijit.form.Form" jsid="form1"> <input dojotype="dijit.form.TextBox" type="text" name="textbox1" value="てきすと1" /> <input dojotype="dijit.form.TextBox" type="text" name="textbox2" value="てきすと2" /> </form>
今度はformを拡張してJavaScript変数のform1に割り当てています。
どんな機能があるかというと、form1.attr('value')とやると{textbox1:"てきすと1",textbox2:"てきすと2"}が返ってきたり。逆にform1.attr('value', {textbox1:"ほえほえ",textbox2:"はにゃ~ん"})と値を初期化できたり。

クラスはたくさんあって、それぞれ機能が違うのでそこは調べてください☆

Dojo基礎文法最速マスター ~JavaScript編~

何はともあれまずは読み込み。 Google AJAX Libraries APIならダウンロード&インストール不要。

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.4/dojo/dojo.xd.js"> </script>
以降はJavaScriptの説明になるので、<script type="text/javascript">~</script>内に書きます。
Dojoは細かくモジュール分けされているので、必要なモジュールは読み込む必要があります。
dojo.require("dijit.form.Button");
などなど。 JavaScriptとhtml読み込み完了後に処理をするにはdojo.addOnLoad()を使います。
dojo.addOnLoad(function(){ ...; // やりたいこと });
JavaScriptについてはほとんど説明することはありません。
というのもこれに続くHTML編とCSS編の説明が必要になるからです。

2009年12月28日月曜日

Hyper-V with PowerShell

Hyper-V Serverを導入しました。これは機能制限されたWindows Server 2008 Server Coreみたいなものです。Server Coreと同じくローカルではコマンドプロンプトでの管理しかありません。 基本的にはfirewallを必要な分解放して、リモートから管理するわけですが、ここはあえてひねくれて、Hyper-V Server単独でどこまでできるかを試してみました。 デフォルトでは有効になっていませんが、

dism /online /enable-feature /featurename:NetFx2-ServerCore /featurename:MicrosoftWindowsPowerShell
とすることでPowerShellが有効になります。 さてこのPowerShell + WMIを使ってHyper-Vは管理できます。 気合いで書いてみました。
# Switch作成 $vsm = gwmi -namespace root\virtualization Msvm_VirtualSwitchManagementService $vs = [wmi]$vsm.CreateSwitch("ExternalNetwork", "ExternalNetwork", 4096).CreatedVirtualSwitch $esp = [wmi]$vsm.CreateSwitchPort($vs, "ExternalNetwork_ExternalPort", "ExternalNetwork_ExternalPort").CreatedSwitchPort $isp = [wmi]$vsm.CreateSwitchPort($vs, "ExternalNetwork_InternalPort", "ExternalNetwork_InternalPort").CreatedSwitchPort $eep = gwmi -namespace root\virtualization Msvm_ExternalEthernetPort #NICが複数ある場合は注意 $vsm.SetupSwitch($esp, $isp, $eep, "ExternalNetwork", "ExternalNetwork") # VM作成、CPU、Memoryまで  $vsm = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService $gsd = (([wmiclass]"root\virtualization:Msvm_CirtualSystemGlobalSettingData").CreateInstance() $gsd .ElementName = "web" $vm = $vsm.DefineVirtualSystem($gsd.GetText([Management.TextFormat]::WmiDtd20)).DefinedSystem $sd = $vm.getRelated("Msvm_VirtualSystemSettingData") | select -first 1 $psd = $sd.getRelated("Msvm_ProcessorSettingData") $psd.VirtualQuantity = 2 $msd = $sd.getRelated("Msvm_MemorySettingData") $msd.Limit = $msd.Reservation = $msd.VirtualQuantity = 1024 $vsm.ModifyVirtualSystemResources($vm, (@($psd, $msd) |% {$_.GetText([Management.TextFormat]::WmiDtd20)})) # NIC追加 $vsm = gwmi -namespace root\virtualization Msvm_VirtualSwitchManagementService $guid = [Guid]::NewGuid().ToString() $sp = $vsm.CreateSwitchPort($vs, $guid, $guid).CreatedSwitchPort $ac = (gwmi -namespace root\virtualization Msvm_AllocationCapabilities -filter "ResourceType=10 and ResourceSubType='Microsoft Synthetic Ethernet Port'").__Path.Replace('\', '\\') # 10=EthernetAdapter $esd = [wmi](gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities -filter "GroupComponent='$ac' and ValueRange=0").PartComponent $esd.Connection = $sp.__Path $esd.ElementName = "Synthetic Ethernet Port" $esd.VirtualSystemIdentifiers = [Guid]::NewGuid().ToString("B") $vsm = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService $vsm.AddVirtualSystemResources($vm, $esd.GetText([Management.TextFormat]::WmiDtd20)) # Disk追加 $im = gwmi -namespace root\virtualization Msvm_ImageManagementService $dir = (gwmi -namespace root\virtualization Msvm_VirtualSystemManagementServiceSettingData).DefaultVirtualHardDiskPath $im.CreateDynamicVirtualHardDisk( (Join-Path $dir "test.vhd"), 127GB ) $ide = ($sd.getRelated("MSVM_ResourceAllocationSettingData")| where {$_.ResourceSubType -eq "Microsoft Emulated IDE Controller" -and $_.Address -eq 0}) $ac = (gwmi -namespace root\virtualization Msvm_AllocationCapabilities -filter "ResourceType=22 and ResourceSubType='Microsoft Synthetic Disk Drive'").__Path.Replace('\', '\\') # 22=Disk $dsd = [wmi](gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities -filter "GroupComponent='$ac' and ValueRange=0").PartComponent $dsd.Parent = $ide.__Path $dsd.Address = 0 $vsm = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService $drive = [wmi]($vsm.AddVirtualSystemResources($vm, $dsd.GetText([Management.TextFormat]::WmiDtd20)).NewResources | select -first 1) $ac = (gwmi -namespace root\virtualization Msvm_AllocationCapabilities -filter "ResourceType=21 and ResourceSubType='Microsoft Virtual Hard Disk'").__Path.Replace('\', '\\') # 21=StorageExtent $dsd = [wmi](gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities -filter "GroupComponent='$ac' and ValueRange=0").PartComponent $dsd.Connection = Join-Path $dir "test.vhd" $dsd.Parent = $drive.__Path $vsm.AddVirtualSystemResources($vm, $dsd.GetText([Management.TextFormat]::WmiDtd20)) # DVD追加 $ac = (gwmi -namespace root\virtualization Msvm_AllocationCapabilities -filter "ResourceType=16 and ResourceSubType='Microsoft Synthetic DVD Drive'").__Path.Replace('\', '\\') # 16=DVDDrive $dsd = [wmi](gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities -filter "GroupComponent='$ac' and ValueRange=0").PartComponent $dsd.Parent = $ide.__Path $dsd.Address = 1 $drive = [wmi]($vsm.AddVirtualSystemResources($vm, $dsd.GetText([Management.TextFormat]::WmiDtd20)).NewResources | select -first 1) $ac = (gwmi -namespace root\virtualization Msvm_AllocationCapabilities -filter "ResourceType=21 and ResourceSubType='Microsoft Virtual CD/DVD Disk'").__Path.Replace('\', '\\') # 21=StorageExtent $dsd = [wmi](gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities -filter "GroupComponent='$ac' and ValueRange=0").PartComponent $dsd.Connection = (gwmi Win32_CdromDrive -filter "Drive='D:'").DeviceID # D:ドライブ $dsd.Parent = $drive.__Path $vsm.AddVirtualSystemResources($vm, $dsd.GetText([Management.TextFormat]::WmiDtd20))
これぐらいでVMが作成できるはず。 ここまで書いてようやく気付きました。VMの画面が見れません。VMにOSがインストールできないわけです…。もちろんP2Vとかすればできますが…。 結局、長いものに巻かれろということで、私もリモート管理することにしました。 というわけで本当に動作確認できていません。