回答編集履歴
3
最後の1行追記
test
CHANGED
@@ -223,3 +223,5 @@
|
|
223
223
|
|
224
224
|
|
225
225
|
設定ファイルを書くDIコンテナは、設定ファイルを読み込んで動作を変更できるようにちょっと変えただけだ。
|
226
|
+
|
227
|
+
設定ファイルを使う場合は、現在アプリケーションに読み込まれてる型情報をリフレクションで取得しておいて、その情報に設定ファイルから得たオプションを適用していく、という形になるだろうね。
|
2
文章の修正
test
CHANGED
@@ -174,7 +174,7 @@
|
|
174
174
|
|
175
175
|
情報を収集し、展開する。
|
176
176
|
|
177
|
-
|
177
|
+
収集方法は別にメソッドでもいいし、一般的なDIコンテナみたいになんらかのファイルでもいい。
|
178
178
|
|
179
179
|
基本は、あるインスタンスの生成方法を集積して、再帰的に呼ぶだけ。
|
180
180
|
|
@@ -202,6 +202,8 @@
|
|
202
202
|
|
203
203
|
|
204
204
|
|
205
|
+
// ISomeClassという型には、ImplemetedClassをインスタンス化してよこせ、と指示を出す。
|
206
|
+
|
205
207
|
container.Bind<ISomeClass>().To<ImplementedClass>();
|
206
208
|
|
207
209
|
|
@@ -214,7 +216,7 @@
|
|
214
216
|
|
215
217
|
ちなみにこれはNinjectっていうC#のDIコンテナを僕が使っているのでその構造に強く影響を受けている。
|
216
218
|
|
217
|
-
NinjectはDIコンテナだけど
|
219
|
+
NinjectはDIコンテナだけど設定ファイルを使わないので、その分プログラマーには直観的だと思う。
|
218
220
|
|
219
221
|
ymlだのXMLだので設定ファイルを書いてインジェクションするよりよっぽど使うのが簡単なので、発想はC#未経験でもページを見ればわかると思う。
|
220
222
|
|
1
追記
test
CHANGED
@@ -24,166 +24,200 @@
|
|
24
24
|
|
25
25
|
|
26
26
|
|
27
|
+
```C#
|
28
|
+
|
29
|
+
// あるクラスのインジェクションに関係する情報を集める
|
30
|
+
|
31
|
+
// これは関数で支持を出しても良いし、よりよい形ではリフレクションでも良い
|
32
|
+
|
33
|
+
BindingInfo<T> Bind<T>()
|
34
|
+
|
35
|
+
{
|
36
|
+
|
37
|
+
// このコンストラクタにどんな情報があるかを事前にまとめておくためのクラスがあるとして
|
38
|
+
|
39
|
+
var info = new BindingInfo(typeof(T));
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
// まずは器を用意しておく
|
44
|
+
|
45
|
+
cache[typeof(type)] = info;
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
return info;
|
50
|
+
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
// で、実装クラスの関連情報を作成した収集クラスに集める
|
56
|
+
|
57
|
+
public class BindingInfo<T>
|
58
|
+
|
59
|
+
{
|
60
|
+
|
61
|
+
// 例えばある型と紐づける
|
62
|
+
|
63
|
+
public BindedTypeInfo To(Type type)
|
64
|
+
|
65
|
+
{
|
66
|
+
|
67
|
+
// 紐づける型が派生形であることを調べる
|
68
|
+
|
69
|
+
this.Type.IsAssignableFrom(type);
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
// C#だとこんな風にコンストラクタの一覧はとってこれるし
|
74
|
+
|
75
|
+
var constructors = type.GetConstructors();
|
76
|
+
|
77
|
+
foreach (var constructor in constructors)
|
78
|
+
|
79
|
+
{
|
80
|
+
|
81
|
+
// ConstructorInfoからはGetParametersとかで引数はとってこれる
|
82
|
+
|
83
|
+
this.Add(new BindingConstructorInfo(constructor));
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
// そもそも、ConstructorInfoは実行できる
|
88
|
+
|
89
|
+
// constructor.Invoke(/*引数はオブジェクトの配列*/);
|
90
|
+
|
91
|
+
}
|
92
|
+
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
// もしくはあるインスタンスと紐づけたり
|
98
|
+
|
99
|
+
public BindedTypeInfo ToConstant(T value)
|
100
|
+
|
101
|
+
{
|
102
|
+
|
103
|
+
// ここでは、この型情報のインスタンスが欲しい時に
|
104
|
+
|
105
|
+
// ここで受け取ったvalueを返すようにする
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
// で、紐づけられた関連情報を更にreturn することによって
|
110
|
+
|
111
|
+
// 細かいオプションを足せるようにしてもいいだろうね!
|
112
|
+
|
113
|
+
}
|
114
|
+
|
115
|
+
}
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
// DIコンテナで値を取得するときは、再帰的に生成を行っていく
|
120
|
+
|
121
|
+
public T Get<T>()
|
122
|
+
|
123
|
+
{
|
124
|
+
|
125
|
+
// ある型の情報からインスタンスを取るために必要なものを考える
|
126
|
+
|
127
|
+
var info = cache[typeof(T)];
|
128
|
+
|
129
|
+
// 例えばinfoがコンスタントならその値を返すだろうし
|
130
|
+
|
131
|
+
if (info.IsConstant)
|
132
|
+
|
133
|
+
{
|
134
|
+
|
135
|
+
return info.ConstantValue;
|
136
|
+
|
137
|
+
}
|
138
|
+
|
139
|
+
else
|
140
|
+
|
141
|
+
{
|
142
|
+
|
143
|
+
// じゃなくてインスタンスを生成しなければならないなら
|
144
|
+
|
145
|
+
// 必要なコンストラクタの引数を生成するために再帰的にGet<T>する
|
146
|
+
|
147
|
+
var constructor = info.GetConstructor();
|
148
|
+
|
149
|
+
var parameters = new List<object>();
|
150
|
+
|
151
|
+
foreach(var parameterInfo in constructor.GetParameters())
|
152
|
+
|
153
|
+
{
|
154
|
+
|
155
|
+
// Getメソッドを再帰的に呼び出せばいつか端にたどり着く
|
156
|
+
|
157
|
+
parameters.Add(this.Get(parameterInfo.ParameterType));
|
158
|
+
|
159
|
+
}
|
160
|
+
|
161
|
+
|
162
|
+
|
163
|
+
// で、生成したパラメータを使ってコンストラクタを実行する
|
164
|
+
|
165
|
+
return constructor.Invoke(parameters);
|
166
|
+
|
167
|
+
}
|
168
|
+
|
169
|
+
}
|
170
|
+
|
27
171
|
```
|
28
172
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
// 紐づける型が派生形であることを調べる
|
68
|
-
|
69
|
-
this.Type.IsAssignableFrom(type);
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
// C#だとこんな風にコンストラクタの一覧はとってこれるし
|
74
|
-
|
75
|
-
var constructors = type.GetConstructors();
|
76
|
-
|
77
|
-
foreach (var constructor in constructors)
|
78
|
-
|
79
|
-
{
|
80
|
-
|
81
|
-
// ConstructorInfoからはGetParametersとかで引数はとってこれる
|
82
|
-
|
83
|
-
this.Add(new BindingConstructorInfo(constructor));
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
// そもそも、ConstructorInfoは実行できる
|
88
|
-
|
89
|
-
// constructor.Invoke(/*引数はオブジェクトの配列*/);
|
90
|
-
|
91
|
-
}
|
92
|
-
|
93
|
-
}
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
// もしくはあるインスタンスと紐づけたり
|
98
|
-
|
99
|
-
public BindedTypeInfo ToConstant(T value)
|
100
|
-
|
101
|
-
{
|
102
|
-
|
103
|
-
// ここでは、この型情報のインスタンスが欲しい時に
|
104
|
-
|
105
|
-
// ここで受け取ったvalueを返すようにする
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
// で、紐づけられた関連情報を更にreturn することによって
|
110
|
-
|
111
|
-
// 細かいオプションを足せるようにしてもいいだろうね!
|
112
|
-
|
113
|
-
}
|
114
|
-
|
115
|
-
}
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
// DIコンテナで値を取得するときは、再帰的に生成を行っていく
|
120
|
-
|
121
|
-
public T Get<T>()
|
122
|
-
|
123
|
-
{
|
124
|
-
|
125
|
-
// ある型の情報からインスタンスを取るために必要なものを考える
|
126
|
-
|
127
|
-
var info = cache[typeof(T)];
|
128
|
-
|
129
|
-
// 例えばinfoがコンスタントならその値を返すだろうし
|
130
|
-
|
131
|
-
if (info.IsConstant)
|
132
|
-
|
133
|
-
{
|
134
|
-
|
135
|
-
return info.ConstantValue;
|
136
|
-
|
137
|
-
}
|
138
|
-
|
139
|
-
else
|
140
|
-
|
141
|
-
{
|
142
|
-
|
143
|
-
// じゃなくてインスタンスを生成しなければならないなら
|
144
|
-
|
145
|
-
// 必要なコンストラクタの引数を生成するために再帰的にGet<T>する
|
146
|
-
|
147
|
-
var constructor = info.GetConstructor();
|
148
|
-
|
149
|
-
var parameters = new List<object>();
|
150
|
-
|
151
|
-
foreach(var parameterInfo in constructor.GetParameters())
|
152
|
-
|
153
|
-
{
|
154
|
-
|
155
|
-
// Getメソッドを再帰的に呼び出せばいつか端にたどり着く
|
156
|
-
|
157
|
-
parameters.Add(this.Get(parameterInfo.ParameterType));
|
158
|
-
|
159
|
-
}
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
// で、生成したパラメータを使ってコンストラクタを実行する
|
164
|
-
|
165
|
-
return constructor.Invoke(parameters);
|
166
|
-
|
167
|
-
}
|
168
|
-
|
169
|
-
}
|
173
|
+
|
174
|
+
|
175
|
+
情報を収集し、展開する。
|
176
|
+
|
177
|
+
それは別にメソッドでもいいし、一般的なDIコンテナみたいになんらかのファイルでもいい。
|
178
|
+
|
179
|
+
基本は、あるインスタンスの生成方法を集積して、再帰的に呼ぶだけ。
|
180
|
+
|
181
|
+
インスタンス化できなければ情報不足として例外を投げればいい。
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
実行時の動作変更用のオプションの拡張、インスタンス化に関する情報のキャッシュで高速化だとか、まあそういう細かいのはいっぱいあるだろうと思う。
|
186
|
+
|
187
|
+
|
188
|
+
|
189
|
+
とりあえず… 既存のOSSのDIコンテナのソースを見よう!
|
190
|
+
|
191
|
+
|
192
|
+
|
193
|
+
#追記
|
194
|
+
|
195
|
+
|
196
|
+
|
197
|
+
上のクラスの使い方の想定をかいてなかったね。
|
198
|
+
|
199
|
+
```C#
|
200
|
+
|
201
|
+
var container = new MyDIContainer();
|
202
|
+
|
203
|
+
|
204
|
+
|
205
|
+
container.Bind<ISomeClass>().To<ImplementedClass>();
|
206
|
+
|
207
|
+
|
208
|
+
|
209
|
+
var implemented = container.Get<ISomeClass>();
|
170
210
|
|
171
211
|
```
|
172
212
|
|
173
213
|
|
174
214
|
|
175
|
-
情報を収集し、展開する。
|
176
|
-
|
177
|
-
|
215
|
+
ちなみにこれはNinjectっていうC#のDIコンテナを僕が使っているのでその構造に強く影響を受けている。
|
178
|
-
|
216
|
+
|
179
|
-
|
217
|
+
NinjectはDIコンテナだけど、設定ファイルを使わない、その分プログラマーには直観的だと思う。
|
180
|
-
|
181
|
-
|
218
|
+
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
219
|
+
ymlだのXMLだので設定ファイルを書いてインジェクションするよりよっぽど使うのが簡単なので、発想はC#未経験でもページを見ればわかると思う。
|
186
|
-
|
187
|
-
|
188
|
-
|
220
|
+
|
221
|
+
|
222
|
+
|
189
|
-
|
223
|
+
設定ファイルを書くDIコンテナは、設定ファイルを読み込んで動作を変更できるようにちょっと変えただけだ。
|