ラベル C# の投稿を表示しています。 すべての投稿を表示
ラベル C# の投稿を表示しています。 すべての投稿を表示

2014年7月3日木曜日

Visual Studio 2013 SDK で拡張機能を作りたい その6

VisualStudioの起動と同時に、インスタンスが生成されるようにしてみた。

    [PackageRegistration(UseManagedResourcesOnly = true)]
    [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
    [ProvideAutoLoad(VSConstants.UICONTEXT.NoSolution_string)]
    [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExists_string)]
    [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionHasMultipleProjects_string)]
    [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionHasSingleProject_string)]
    [ProvideOptionPage(typeof(Properties), "DteEventView", "General", 0, 0, true)]
    [Guid(GuidList.guidVSPackage5PkgString)]
    public sealed class VSPackage5Package : Package
    {

多少、力技な気がしなくもないが・・・

拡張機能は、基本的には使うとき(呼ばれた時)にインスタンスが生成される。
そうでなければ、VisualStudioの起動が重くなる。
しかしイベントハンドラは、最初に登録しないと、他にやるタイミングがないよな。

2014年6月25日水曜日

Visual Studio 2013 SDK で拡張機能を作りたい その4

実は、マクロとアドインとSDKの違いを知らなかった。

マクロ 既に廃止されたので知らない
アドイン DTEというCOMを相手にする・・・VS2013では非推奨
(新しいプロジェクト>その他のプロジェクトの種類>機能拡張>Visual Studio アドイン)
VSPackage
(SDK)
MEFで注入!DTEも使える
(新しいプロジェクト>その他のプロジェクトの種類>機能拡張>Visual Studio Package)

アドインは、VSPackageに変換できるようだ。(msdn: アドインを VSPackage に変換する)
というわけで、DTEから攻めることにする。

EnvDTE80(DTE2)

*EnvDTE80は、EnvDTE(_DTE)のすべてを含む。

ActiveDocument アクティブドキュメントを取得します。
ActiveSolutionProjects 現在選択されているプロジェクトの配列を取得します。
ActiveWindow 現在アクティブなウィンドウ、または他にアクティブなウィンドウがない場合は最前面に表示されたウィンドウを返します。
AddIns 現在使用できるすべてのアドインを含む AddIns コレクションを取得します。
Application インフラストラクチャ。マイクロソフト内部でのみ使用します。
CommandBars 開発環境のコマンド バーへの参照を取得します。
CommandLineArguments コマンド ライン引数を表す文字列を取得します。
Commands Commands コレクションを返します。
ContextAttributes ContextAttributes コレクションを取得します。このコレクションを使用すると、オートメーション クライアントは、[ダイナミック ヘルプ] ウィンドウで現在選択されている項目に新しい属性を追加し、追加した属性のコンテキスト ヘルプを表示できます。
Debugger デバッガー オブジェクトを取得します。
DisplayMode 表示モード (MDI またはタブ付きドキュメント) を取得します。
Documents 開発環境で開いているドキュメントのコレクションを取得します。
DTE トップレベルの機能拡張オブジェクトを取得します。
Edition 環境のエディションの説明を取得します。
Events Events オブジェクトへの参照を取得します。
FileName インフラストラクチャ。マイクロソフト内部でのみ使用します。
Find グローバル テキスト検索処理を表す Find オブジェクトを取得します。
FullName オブジェクトのファイルの完全パスと名前を取得します。
Globals ソリューション (.sln) ファイル、プロジェクト ファイル、またはユーザーのプロファイル データに保存できるアドイン値を格納する Globals オブジェクトを取得します。
IsOpenFile インフラストラクチャ。マイクロソフト内部でのみ使用します。
ItemOperations ItemOperations オブジェクトを取得します。
LocaleID 開発環境を実行しているロケールの ID を取得します。
Macros Macros オブジェクトを取得します。
MacrosIDE マクロ IDE のオートメーション モデルのルートを取得します。
MainWindow メイン開発環境ウィンドウを表す Window オブジェクトを取得します。
Mode 開発環境のモード (デバッグまたはデザイン) を取得します。
Name _DTE オブジェクトの名前を設定または取得します。
ObjectExtenders ObjectExtenders オブジェクトを取得します。
Properties [ツール] メニューの [オプション] ダイアログ ボックスで使用できるすべてのカテゴリとサブカテゴリを表す Properties コレクションを返します。
RegistryRoot Visual Studio レジストリ設定のルートへのパスを含む文字列を取得します。
SelectedItems 環境で現在選択されている項目を含むコレクションを取得します。
Solution 現在の環境のインスタンスで開いているすべてのプロジェクトを表し、ビルド オブジェクトにアクセスできる Solution オブジェクトを取得します。
SourceControl オブジェクトの背後にあるファイルのソース コード管理の状態を操作できる、SourceControl オブジェクトを取得します。
StatusBar メイン開発環境ウィンドウのステータス バーを表す StatusBar オブジェクトを取得します。
SuppressUI オートメーション コードの実行中に、UI を表示するかどうかを示す値を取得または設定します。
ToolWindows ツール ウィンドウを検索するためのショートカットとして使用されている ToolWindowsオブジェクトを取得します。
UndoContext グローバル UndoContext オブジェクトを取得します。
UserControl 環境がユーザーまたはオートメーションのどちらによって起動されたかを示す値を設定または取得します。
Version ホスト アプリケーションのバージョン番号を取得します。
WindowConfigurations 使用できるすべてのウィンドウの構成を表す WindowConfigurations コレクションを取得します。
Windows オブジェクトで表示されるウィンドウを含む Windows コレクションを取得します。

EnvDTE90

Debugger3 Debugger3 を使用すると、デバッガーの状態やデバッグ中のプログラムの状態を問い合わせたり、操作したりできます。 Debugger3 は、Debugger2 インターフェイスおよび Debugger インターフェイスよりも優先されます。
ExceptionGroups デバッガーの初回例外のダイアログで使用可能なトップレベルのグループを表します。
ExceptionSettings ExceptionSetting オブジェクトのコレクションです。各オブジェクトは、デバッガーの例外設定のセットを表します。
HTMLWindow3 Visual Studio 統合開発環境 (IDE: Integrated Development Environment) の HTML ドキュメント ウィンドウを表します。
Module デバッグ中のプロセス内のモジュールを表します。
Modules デバッグ中のプロセスで使用可能なモジュールのコレクションを表します。
Process3 Process3 オブジェクトは、プロセスのチェックおよび操作に使用されます。 Process3 オブジェクトは、Process2 オブジェクトおよび Process オブジェクトよりも優先されます。
Solution3 統合開発環境 (IDE: Integrated Development Environment) のすべてのプロジェクトとソリューション全体のプロパティを表します。 Solution および Solution2 に代わるものです。
Template 統合開発環境 (IDE: Integrated Development Environment) の現在のインスタンスで使用できる Visual Studio テンプレートを表します。
Templates 現在のプロジェクトにあるすべてのテンプレートを表します。
Thread2 Visual Studio アプリケーション内のスレッドを表します。
ToolBoxTab3 [ツールボックス] のタブとそのタブに含まれるすべてのオブジェクトを表します。 ToolBoxTab3は、ToolBoxTab インターフェイスと ToolBoxTab2 インターフェイスに代わるものです。

EnvDTE100

Debugger5 Debugger5 を使用して、デバッガーの状態やデバッグ中のプログラムの状態を問い合わせたり、操作したりできます。 Debugger5 は、Debugger4 インターフェイスよりも優先されます。
Expression2 Expression2 オブジェクトには、式の評価で返されたアイテムをチェックするプロパティが格納されます。
Solution4 統合開発環境 (IDE: Integrated Development Environment) のすべてのプロジェクトとソリューション全体のプロパティを表します。 Solution , Solution2 および Solution3 よりも優先されます。

長くなったので、ここまで。

2014年6月20日金曜日

コレクションの初期化 Repeat or Range

参照型のコレクションを、インスタンス込みで初期化したい時がある。

なんか動きがおかしいので、デバッグしていたら、以下の様なことがわかった。

    int numOfFoo = 3;

    // newが1回だけ実行され、その結果が3回使われる。
    // コレクションの要素数は3だが、全て同じインスタンスが入っている。
    var listX = Enumerable.Repeat(new Foo(), numOfFoo).ToList();

    // newが3回実行される。
    // コレクションの要素数は3で、別々のインスタンスが入っている。
    var listO = Enumerable.Range(0, numOfFoo).Select((x) => new Foo()).ToList();

配列の初期化にRepeatを使っていたので、同じように書いたらダメダメだった。
気をつけよう。

2014年6月19日木曜日

Visual Studio 2013 SDK で拡張機能を作りたい その1

Microsoft Visual Studio 2013 SDKをインスコすると、機能拡張のプロジェクトが作れるようになる。



言語はC# を選択する。


空のプロジェクトを作りたいので、何も選択しない。

とりあえずなので、ユニットテストも不要

ソリューションができたので、実行してみる。

VisualStudioがもうひとつ起動すればOK

今日はここまで。

2014年6月13日金曜日

NET Framework のバージョンを表すシンボル定義

色々探したが、よい物が見つからなかった。
なので、作ってみた。

<None Include="App.config" />
  </ItemGroup>
  <Import Project="$(SolutionDir)NetFrameworkVersion.targets" />
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <PropertyGroup>
  <PreBuildEvent>

これで、以下のシンボルが定義される。

  • NET_20
  • NET_30
  • NET_35
  • NET_40
  • NET_45
  • NET_451
  • NET_20_OR_GREATER
  • NET_30_OR_GREATER
  • NET_35_OR_GREATER
  • NET_40_OR_GREATER
  • NET_45_OR_GREATER


このファイルを、ソリューションフォルダに置くのを忘れずに。
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    
    <!-- NET Frameworkのバージョンに関する定数を定義する。 -->
    <!-- NET_20, NET_30, NET_35, NET_40, NET_45, NET_451, -->
    <!-- NET_20_OR_GREATER, NET_30_OR_GREATER, NET_35_OR_GREATER, NET_40_OR_GREATER, NET_45_OR_GREATER -->

    <!-- メジャーバージョン、マイナーバージョン、ビルド番号の結果を入れる -->
    <VerMajor>0</VerMajor>
    <VerMinor>0</VerMinor>
    <VerBuild>0</VerBuild>

    <!-- Pos1:最初のピリオドの位置 / Pos2:次のピリオドの位置 / Pos1n,Pos2nは、それぞれのPosに+1している -->
    <Pos1>-1</Pos1>
    <Pos1n>-1</Pos1n>
    <Pos2>-1</Pos2>
    <Pos2n>-1</Pos2n>

    <!-- v4.5.1とかv2.0とか入っているので、まずは'v'を除去 -->
    <Tmp>$(TargetFrameworkVersion.Replace('v', ''))</Tmp>

    <!-- ピリオドがなければPos1に-1が入るので、Pos2に突入させない-->
    <Pos1>$(Tmp.IndexOf("."))</Pos1>
    <Pos1n>$([MsBuild]::Add($(Pos1), 1))</Pos1n>
    <Pos2 Condition="0 &lt;= $(Pos1)">$(Tmp.IndexOf(".", $([MsBuild]::Add($(Pos1), 1))))</Pos2>
    <Pos2n>$([MsBuild]::Add($(Pos2), 1))</Pos2n>
    
    <!-- 最初のピリオドがあれば、そこまでを VerMajor にする。ピリオドがなければ、全てを VerMajor にする。-->
    <VerMajor  Condition="0 &lt;= $(Pos1)">$(Tmp.SubString(0, $(Pos1)))</VerMajor>
    <VerMajor  Condition="0 &gt;  $(Pos1)">$(Tmp)</VerMajor>

    <!-- 次のピリオドがあれば、 最初のピリオドから次のピリオドまでを、VerMinorにする。なければ、残りをVerMinorにする-->
    <VerMinor  Condition="0 &lt;= $(Pos2)">$(Tmp.SubString($(Pos1n), $([MsBuild]::Subtract($(Pos2), $(Pos1n)))))</VerMinor>
    <VerMinor  Condition="0 &gt;  $(Pos2) And 0 != $(Pos1n)">$(Tmp.SubString($(Pos1n)))</VerMinor>
    
    <!--2つ目のピリオドがあれば、そこから後ろを VerBuild にする-->
    <VerBuild  Condition="0 &lt;= $(Pos2)">$(Tmp.SubString($(Pos2n)))</VerBuild>

    <!-- VerMajor,VerMinor,VerBuildを用いて、定数を作成する。 -->
    <DefineConstants>$(DefineConstants);NET_$(VerMajor)$(VerMinor)$(VerBuild)</DefineConstants>
    <DefineConstants Condition="2 &lt;= $(VerMajor)">$(DefineConstants);NET_20_OR_GREATER</DefineConstants>
    <DefineConstants Condition="3 &lt;= $(VerMajor)">$(DefineConstants);NET_30_OR_GREATER</DefineConstants>
    <DefineConstants Condition="3 &lt;= $(VerMajor) And 5 &lt;= $(VerMinor)">$(DefineConstants);NET_35_OR_GREATER</DefineConstants>
    <DefineConstants Condition="4 &lt;= $(VerMajor)">$(DefineConstants);NET_40_OR_GREATER</DefineConstants>
    <DefineConstants Condition="4 &lt;= $(VerMajor) And 5 &lt;= $(VerMinor)">$(DefineConstants);NET_45_OR_GREATER</DefineConstants>

  </PropertyGroup>

</Project>

csproj (MsBuild) のデバッグ

csprojファイルをいじるときに、他の人はどうやってデバッグしているのだろうか?

サンプルとして、TargetFrameworkVersionの先頭に"NET_"をつけて、TestPropertyに入れて、DefineConstantsに追加した。
  <None Include="App.config" />
  </ItemGroup>
  
  <PropertyGroup>
    <TestProperty>NET_$(TargetFrameworkVersion.Replace("v","").Replace(".",""))</TestProperty>
    <DefineConstants>$(DefineConstants);$(TestProperty)</DefineConstants>
  </PropertyGroup>
  
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <!-- To modify your build process, add your task inside one of the ta .... 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
  <Target Name="Build">
    <Message Text="テストプロパティ = $(TestProperty)" />
    <Message Text="ビルド定数       = $(DefineConstants)" />
  </Target>
</Project>

このように、Visual Studioのコマンドプロンプトから、MsBuildを実行すると、Messageタスクが出力される。


このNET_45というシンボルは、ちゃんとVisualStudioで使える。


今度はターゲットフレームワークをNet4.0にすると、シンボル名もNET_40になる。

当然、NET_45シンボルは無いので、#if で括った部分は無効になる。

2014.06.18追記
csprojで使えるメソッドとかの説明
http://msdn.microsoft.com/ja-jp/library/dd633440.aspx

2014年6月4日水曜日

Collection クラス

コレクションの雛形なんだけど、実はC# 2.0からあったんだね。

/// <summary>上限付きコレクション</summary>
public class LimitedCollection<T> : Collection<T>
{
    private int limit = int.MaxValue;

    public int Limit
    {
        get
        {
            return this.limit;
        }

        set
        {
            this.limit = value;
            this.CheckLimit();
        }
    }

    private void CheckLimit()
    {
        if (this.Limit <= this.Count)
        {
            throw new InvalidOperationException();
        }
    }

    protected override void SetItem(int index, T item)
    {
        this.CheckLimit();
        base.SetItem(index, item);
    }

    protected override void InsertItem(int index, T item)
    {
        this.CheckLimit();
        base.InsertItem(index, item);
    }
}

2014年2月15日土曜日

Visual Studio Expressで、StyleCopを使う [改良版]

前回の方法だと、毎回StyleCopが走ってうざい。
とくに、実装中やデバッグ中のコードスタイルを指摘されるとキレそうになる。
だいいち、ワーニングとか見づらいし。

なので、Releaseビルド時のみチェックを走らせるようにした。

<Import Condition="Exists('$(ProgramFiles)\MSBuild\StyleCop\v4.7\StyleCop.targets') and '$(Configuration)' != 'Debug'"
        Project="$(ProgramFiles)\MSBuild\StyleCop\v4.7\StyleCop.targets" />

これで、デバッグ中はスッキリするようになった。

2014年2月12日水曜日

かっこいい電卓を3分で作る方法

こんな電卓をWPFで作ってみた



まず、WPFプロジェクトを作成し、NuGetでExtended WPF ToolKitを追加する。


次に、MainWindow.xamlに以下の行を追加する。

<Window x:Class="Calculator.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpftoolkit="http://schemas.xceed.com/wpf/xaml/toolkit"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <wpftoolkit:Calculator/>
    </Grid>
</Window>

貼り付けただけで、作ってないな。

2014年2月11日火曜日

Extended WPF Toolkit 無料版 (Community Edition)

どんなコントロールがあるのか φ(..)メモメモ
例によってグーグル先生に聞いてみた。括弧内はWindows.Formsのコントロールに対応

  • AvalonDock (要はIDEみたいなドッキングウィンドウ)
  • AutoSelectTextBox (要はフォーカス時に選択状態になるTextBox)
  • BusyIndicator (要はProgressBar)
  • ButtonSpinner (要はNumericUpDown)
  • Calculator (要は電卓)
  • CalculatorUpDown (要は電卓とNumericUpDownの合体)
  • CheckComboBox (要は複数選択可能なComboBox+CheckListBox)
  • CheckListBox (要はCheckListBoxそのもの)
  • ChildWindow (要は中身を自由に作れるMessageBox)
  • CollectionEditor (要はPropertyGridのコレクションエディタ)
  • DataGrid (要は高速DataGrid)
  • CollectionControlDialog (要はPropertyGridのコレクションエディタのダイアログ版)
  • ColorCanvas (要はペイントツール等の色をつくる画面)
  • ColorPicker (要はColorDialogの中身の高機能版)
  • DateTimePicker (要はDateTimePickerのカレンダーが出た状態)
  • DateTimeUpDown (要はUpDownで日付時刻が変更できるDateTimePicker)
  • DecimalUpDown (要はDecimal?対応NumericUpDown)
  • DoubleUpDown (要はDouble?対応NumericUpDown)
  • DropDownButton (要はPanelのドロップダウンなボタン)
  • IntegerUpDown (要はInt?対応NumericUpDown)
  • Magnifier (要はルーペ機能)
  • MaskedTextBox (要はMaskedTextBox)
  • MessageBox (要はMessageBox)
  • MultiLineTextEditor (要はドロップダウンなTextBoxのMultiLineをTrue)
  • Pie (要は円弧のシェイプ)
  • PrimitiveTypeCollectionEditor (要はドロップダウンなコレクションエディタ??)
  • PropertyGrid (要はPropertyGrid)
  • RichTextBox (要はRichTextBox)
  • RichTextBoxFormatBar (要はRichTextBoxのツールバー:フォントや右寄せ)
  • SplitButton (ドロップダウンでパネルを表示するベースクラス??)
  • SwitchPanel
  • RandomPanel
  • WrapPanel
  • TimelinePanel (要は日付時刻に添ってレイアウトするパネル)
  • TimePicker (要はDateTimeUpDown の時間専用版)
  • WatermarkTextBox (要は入力して欲しい内容を薄く表示するTextBox)
  • WindowContainer (要は何だろ?)
  • Wizard (要はWizardを単一フォームで実現)
  • Zoombox (要は)

2014年2月5日水曜日

Visual Studio Expressで、StyleCopを使う

ソリューションエクスプローラで、プロジェクトをアンロードすると、右クリックメニューでプロジェクトファイルを編集できる。

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Condition="Exists('$(ProgramFiles)\MSBuild\StyleCop\v4.7\StyleCop.targets')" 
Project="$(ProgramFiles)\MSBuild\StyleCop\v4.7\StyleCop.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

こんなんを用意して、スニペットに登録すると楽だよ
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<Header>
<Title>ExpressでStyleCop</Title>
<Author>Jun</Author>
<Description>Ver4.7系に限定!あらかじめStyleCopのインスコが必要です。</Description>
<SnippetTypes>
<SnippetType>SurroundsWith</SnippetType>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Code Language="XML">
<![CDATA[<Import Condition="Exists('$$(ProgramFiles)\MSBuild\StyleCop\v4.7\StyleCop.targets')" 
Project="$$(ProgramFiles)\MSBuild\StyleCop\v4.7\StyleCop.targets"/>
]]>
</Code>
</Snippet>
</CodeSnippet>

2013年11月27日水曜日

Visual Studio Express で、 NUnitを使う

もう出尽くした感のあるネタだが、ネットで良い方法を見つけたのでメモしておく。

まず、テストプロジェクトの出力の種類を「Windowsアプリケーション」にする。
(通常のテストプロジェクトは、「クラスライブラリ」である)


そして、ダミーのエントリーポイントを追加する。

// 参照設定にnunit-gui-runner.dllを追加
public class NUnitTestRunner
{
    [STAThread]
    static void Main(string[] args)
    {
        NUnit.Gui.AppEntry.Main(
            new string[] { Application.ExecutablePath, "/run"});
    }
}

テストプロジェクトを、スタートアッププロジェクトに設定してRunすると、見慣れたテストランナーが起動する!
テストコード内でブレークポイントも使える。

GUIが目障りな場合は、出力ウィンドウに結果のみ表示させることもできる。
テストプロジェクトの出力の種類を「コンソールアプリケーション」にして、エントリーポイントを以下のようにする。

// 参照設定にnunit-console-runner.dllを追加
public class NUnitTestRunner
{
    [STAThread]
    static void Main(string[] args)
    {
        NUnit.ConsoleRunner.Runner.Main(
            new string[] { Assembly.GetEntryAssembly().Location });
    }
}

出力ウィンドウに結果が。
################################ UNIT TESTS ################################
Running tests in 'C:\Users\xxx\Desktop\NUnitExample\NUnitTest\bin\Debug\NUnitTest.EXE'...
スレッド 0x1580 はコード 259 (0x103) で終了しました。
############################################################################
##############                 S U C C E S S               #################
############################################################################
Executed tests       : 1
Ignored tests        : 0
Failed tests         : 0
Unhandled exceptions : 0
Total time           : 0.0203104881145478 seconds
############################################################################

テストランナーのDLLは、NuGetでNUnit.Runnersでインストールできる。
ソリューションフォルダ以下、packages\NUnit.Runners.2.6.3\tools\lib にある。

<xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="NUnit" version="2.6.3" targetFramework="net45" />
  <package id="NUnit.Runners" version="2.6.3" />
</packages>

2013年11月15日金曜日

C#のデバッグに便利な属性

DebuggerDisplay属性は結構昔からあるが、表示内容のカスタマイズができなくて不便だった。それを打破する方法を見つけた。

[DebuggerDisplay("なまえ={Name}, ねんれい={Age.ToString(\"X\")}")]
public class Example
{
    [DebuggerDisplay("非公開", Name = "名前")]
    public string Name { get; set; }

    [DebuggerDisplay("非公開", Name = "年齢")]
    public int Age { get; set; }

    [DebuggerStepThrough]
    public Example()
    {
        this.Name = "未定";
        this.Age = 255;
    }
}

ダブルクォーテーションにエスケープ文字をつけるのがポイントである。これで、ToStringにより表示形式を変更できる。ちなみに中括弧はエラーになるので、String.Formatは使えない。また、@文字列も使えない。


年齢が16進数になっているところに注目!

ToStringをオーバーライドすればいいんだけどね・・・

2013年11月14日木曜日

C#で契約プログラミング

NetFramework4で契約プログラミングがサポートされたのは知っていたが、高価なVisualStudioだけかと思っていた。ところがプロ版でも使えるということを知ったので、実験してみた。

まずVisualStudioに、拡張機能を追加する。

そして、コンソールアプリケーションを新規作成する。

using System.Diagnostics.Contracts;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 3;
            int b = 2;
            Console.WriteLine("{0} / {1} = {2}", a, b, Program.Div(a, b));

            Console.ReadLine();
        }

        public static int Div(int a, int b)
        {
            
            Contract.Requires(b != 0);                  // 入力の契約
            Contract.Ensures(Contract.Result() >= 0);   // 出力の契約

            return a / b;
        }
    }
}

プロジェクトのプロパティに、見慣れないものが??


わざとb=0にしてコンパイルすると・・・

static void Main(string[] args)
{
    int a = 3;
    int b = 0;
    
    Console.WriteLine("{0} / {1} = {2}", a, b, Program.Div(a, b));

    Console.ReadLine();
}



実行しなくても、ちゃんと契約違反を見つけてくれる!

面白い機能なのだが、漫坊的には採用NGの判定となった。
  1. ExpressEditionでコンパイルできない
    べつに拡張機能が使えるようにしろよ、とか言うつもりはないが、開発関係者全員がプロ版を使えるわけではないので、これは痛い。
    ソースの関連行が無効になってくれたらよいのだが。
  2. 重い
    こんな小さなソースでも、7秒くらいかかる。まるでVS2012のWPFデバッグ開始みたいだ。とても毎回実行したいと思わない。

ExpressEditionでビルドができて、MSBuildで自動化ができるようになったら、再び検討してみるつもりである。