Unity+app.configでHello, wolrd
app.configを使ってIoC(制御の反転)をしてみます。本当はもっと複雑なことをしたいのですが、意外とconfigファイルを作成するのに手間取ったのでまずは簡単な例を作って注意点を探ります。
前準備
NuGetから「Unity」をインストールしておいてください。
Main.vb
Imports Microsoft.Practices.Unity Imports Microsoft.Practices.Unity.Configuration Imports Microsoft.Practices.ServiceLocation Module Module1 Sub Main() '注意! 'LoadConfigurationは拡張メソッドなので、 'Imports Microsoft.Practices.Unity.Configuration 'をしないと利用できません。 Dim container As New UnityContainer container.LoadConfiguration() Dim service As New UnityServiceLocator(container) ServiceLocator.SetLocatorProvider(Function() service) Dim p = ServiceLocator.Current.GetInstance(Of IPerson)() Console.WriteLine(p.Say()) Console.WriteLine("何かキーを押してください") Console.ReadKey() End Sub End Module Public Interface IPerson Function Say() As String End Interface Public Class Person Implements IPerson Public Function Say() As String Implements IPerson.Say Return "Hello, wolrd." End Function End Class
簡単にIoCなところを説明するとDim p = ServiceLocator.Current.GetInstance(Of IPerson)()
と書いた後、インスタンスもせずにConsole.WriteLine(p.Say())
とかメソッドを読んでるところ。VBのコードを追っかけても、p
に何がはまっているのか全くわかりませんね。*1これは後述する「app.config」を見るとわかりますので、しばし無視しましょう。
では本題である注意点を列挙。
- コメントにも書いてありますが、ポイントは
Imports Microsoft.Practices.Unity.Configuration
コレ。configファイルで制御したいなら名前空間のインポートを忘れずに。 - ソースコードには書いてありませんが、このアプリの「名前空間」と「アセンブリ名」は「UnityConfigSample」です。名称は任意でよいのですが、名前空間と、アセンブリ名はあとで使うので覚えておきましょう。
本題ではないですが、上記のサンプルはServiceLocator
を使用してインスタンスを取り出しています。これはシングルトンで実装されてますので、どこからでもServiceLocator.Current.GetInstance(Of T)
とすることでインスタンスを生成することができます。コンソールアプリではUnityServiceLocator
を直利用すればいいと思いますが、複数画面があるアプリの場合はServiceLocator
を使用するとよいでしょう。
app.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <container> <register type="UnityConfigSample.IPerson, UnityConfigSample" mapTo="UnityConfigSample.Person, UnityConfigSample" /> </container> </unity> </configuration>
ここのregister
セクションにて、「IPersonの実体はPersonだ」と指定しています。
ソースコードの外で指定しているのがミソ。このコード自体の実用性はありませんが、これがわからないと次に進めないのでそういうもんかと思ってください。私も勉強中ですので…
configSectionsセクション
configSections
におまじない<section name="unity"…
を書く。
気を付けないといけないのは、他のサイトからコピペしたとき、
<!--注意 この記述だと今のUnity(2.1.505.0)では動きません--> <section name="unity" type= "Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
こう書いてあることがあります。これは「Unityのバージョンは1.1.0.0」と指定しているので、Unityのバージョンに違いがあるとこけます*2。省略するとバージョン縛りはありませんので、省略をするか、適切なバージョン番号を指定してください。
unityセクション
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"><container>…</container></unity>
は決まり文句だと思ってください。とりあえずそのまま書く。
注意すべき個所はregister
。ここにインターフェイスと、マッピングする実体クラスを指定します。見ればなんとなくわかりますね。書式が「型正式名, アセンブリ名」であることに注意してください。
以下のように書いても動きません。
<!--駄目な例1--> <register type="IPerson" mapTo="Person" />
<!--駄目な例2--> <register type="UnityConfigSample.IPerson" mapTo="UnityConfigSample.Person" />
System.InvalidOperationException はハンドルされませんでした。
Message=The type name or alias IPerson could not be resolved. Please check your configuration file and verify this type name.
ちゃんと書きましょう。
<!--正しい書式--> <register type="UnityConfigSample.IPerson, UnityConfigSample" mapTo="UnityConfigSample.Person, UnityConfigSample" />
registerの書き方(別法)
実はregister
の書き方は何通りかあります。他のサイトを参考にした際、下記の記述を使用している場合がありますので、こっちの書き方も知っておきましょう。
alias
別名を付けることができます。
<!--こう書いてもいい--> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <alias alias="IPerson" type="UnityConfigSample.IPerson, UnityConfigSample" /> <alias alias="Person" type="UnityConfigSample.Person, UnityConfigSample" /> <container> <register type="IPerson" mapTo="Person" /> </container> </unity>
<!--alias name は(わかりやすいかはともかく)任意の名前でよい--> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <alias alias="hoge" type="UnityConfigSample.IPerson, UnityConfigSample" /> <alias alias="fugo" type="UnityConfigSample.Person, UnityConfigSample" /> <container> <register type="hoge" mapTo="fugo" /> </container> </unity>
namespace, assembly
検索対象となる名前空間、アセンブリを登録しておくことで記述を省略できます。
<!--こう書いてもいい--> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <namespace name="UnityConfigSample" /> <assembly name="UnityConfigSample" /> <container> <register type="IPerson" mapTo="Person" /> </container> </unity>