1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Dynamic;
5
using System.Reflection;
6
7
namespace Yb.Data.Provider
8 {
9 [Serializable]
10
public
class ExtensionObject: DynamicObject, IDynamicMetaObjectProvider
11 {
12
object _instance;
13
14 Type _instanceType;
15 PropertyInfo[] _cacheInstancePropertyInfos;
16 IEnumerable<PropertyInfo> _instancePropertyInfos
17 {
18
get
19 {
20
if (_cacheInstancePropertyInfos ==
null && _instance !=
null)
21 _cacheInstancePropertyInfos = _instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
22
return _cacheInstancePropertyInfos;
23 }
24 }
25
26
public ExtensionObject()
27 {
28 Initialize(
this);
29 }
30
31
///
<remarks>
32
///
You can pass in null here if you don't want to
33
///
check native properties and only check the Dictionary!
34
///
</remarks>
35
///
<param name="instance"></param>
36
public ExtensionObject(
object instance)
37 {
38 Initialize(instance);
39 }
40
41
42
protected
virtual
void Initialize(
object instance)
43 {
44 _instance = instance;
45
if (instance !=
null)
46 _instanceType = instance.GetType();
47 }
48
49
///
<param name="binder"></param>
50
///
<param name="result"></param>
51
///
<returns></returns>
52
public
override
bool TryGetMember(GetMemberBinder binder,
out
object result)
53 {
54 result =
null;
55
56
//
first check the Properties collection for member
57
if (Properties.Keys.Contains(binder.Name))
58 {
59 result = Properties[binder.Name];
60
return
true;
61 }
62
63
64
//
Next check for Public properties via Reflection
65
if (_instance !=
null)
66 {
67
try
68 {
69
return GetProperty(_instance, binder.Name,
out result);
70 }
71
catch (Exception)
72 { }
73 }
74
75
//
failed to retrieve a property
76
return
false;
77 }
78
79
///
<param name="binder"></param>
80
///
<param name="value"></param>
81
///
<returns></returns>
82
public
override
bool TrySetMember(SetMemberBinder binder,
object value)
83 {
84
85
//
first check to see if there's a native property to set
86
if (_instance !=
null)
87 {
88
try
89 {
90
bool result = SetProperty(_instance, binder.Name, value);
91
if (result)
92
return
true;
93 }
94
catch { }
95 }
96
97
//
no match - set or add to dictionary
98
Properties[binder.Name] = value;
99
return
true;
100 }
101
102
///
<param name="binder"></param>
103
///
<param name="args"></param>
104
///
<param name="result"></param>
105
///
<returns></returns>
106
public
override
bool TryInvokeMember(InvokeMemberBinder binder,
object[] args,
out
object result)
107 {
108
if (_instance !=
null)
109 {
110
try
111 {
112
//
check instance passed in for methods to invoke
113
if (InvokeMethod(_instance, binder.Name, args,
out result))
114
return
true;
115 }
116
catch (Exception)
117 { }
118 }
119
120 result =
null;
121
return
false;
122 }
123
124
///
<param name="instance"></param>
125
///
<param name="name"></param>
126
///
<param name="result"></param>
127
///
<returns></returns>
128
protected
bool GetProperty(
object instance,
string name,
out
object result)
129 {
130
if (instance ==
null)
131 instance =
this;
132
133
var miArray = _instanceType.GetMember(name, BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Instance);
134
if (miArray !=
null && miArray.Length >
0)
135 {
136
var mi = miArray[
0];
137
if (mi.MemberType == MemberTypes.Property)
138 {
139 result = ((PropertyInfo)mi).GetValue(instance,
null);
140
return
true;
141 }
142 }
143
144 result =
null;
145
return
false;
146 }
147
148
///
<param name="instance"></param>
149
///
<param name="name"></param>
150
///
<param name="value"></param>
151
///
<returns></returns>
152
protected
bool SetProperty(
object instance,
string name,
object value)
153 {
154
if (instance ==
null)
155 instance =
this;
156
157
var miArray = _instanceType.GetMember(name, BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.Instance);
158
if (miArray !=
null && miArray.Length >
0)
159 {
160
var mi = miArray[
0];
161
if (mi.MemberType == MemberTypes.Property)
162 {
163 ((PropertyInfo)mi).SetValue(_instance, value,
null);
164
return
true;
165 }
166 }
167
return
false;
168 }
169
170
///
<param name="instance"></param>
171
///
<param name="name"></param>
172
///
<param name="args"></param>
173
///
<param name="result"></param>
174
///
<returns></returns>
175
protected
bool InvokeMethod(
object instance,
string name,
object[] args,
out
object result)
176 {
177
if (instance ==
null)
178 instance =
this;
179
180
//
Look at the instanceType
181
var miArray = _instanceType.GetMember(name,
182 BindingFlags.InvokeMethod |
183 BindingFlags.Public | BindingFlags.Instance);
184
185
if (miArray !=
null && miArray.Length >
0)
186 {
187
var mi = miArray[
0]
as MethodInfo;
188 result = mi.Invoke(_instance, args);
189
return
true;
190 }
191
192 result =
null;
193
return
false;
194 }
195
196
public
object
this[
string key]
197 {
198
get
199 {
200
try
201 {
202
//
try to get from properties collection first
203
return Properties[key];
204 }
205
catch (KeyNotFoundException ex)
206 {
207
//
try reflection on instanceType
208
object result =
null;
209
if (GetProperty(_instance, key,
out result))
210
return result;
211
212
//
nope doesn't exist
213
throw;
214 }
215 }
216
set
217 {
218
if (Properties.ContainsKey(key))
219 {
220 Properties[key] = value;
221
return;
222 }
223
224
//
check instance for existance of type first
225
var miArray = _instanceType.GetMember(key, BindingFlags.Public | BindingFlags.GetProperty);
226
if (miArray !=
null && miArray.Length >
0)
227 SetProperty(_instance, key, value);
228
else
229 Properties[key] = value;
230 }
231 }
232
233
///
<param name="includeInstanceProperties"></param>
234
///
<returns></returns>
235
public IEnumerable<KeyValuePair<
string,
object>> GetProperties(
bool includeInstanceProperties =
false)
236 {
237
if (includeInstanceProperties && _instance !=
null)
238 {
239
foreach (
var prop
in
this._instancePropertyInfos)
240
yield
return
new KeyValuePair<
string,
object>(prop.Name, prop.GetValue(_instance,
null));
241 }
242
243
foreach (
var key
in
this.Properties.Keys)
244
yield
return
new KeyValuePair<
string,
object>(key,
this.Properties[key]);
245
246 }
247
248
///
<param name="item"></param>
249
///
<param name="includeInstanceProperties"></param>
250
///
<returns></returns>
251
public
bool Contains(KeyValuePair<
string,
object> item,
bool includeInstanceProperties =
false)
252 {
253
bool res = Properties.ContainsKey(item.Key);
254
if (res)
255
return
true;
256
257
if (includeInstanceProperties && _instance !=
null)
258 {
259
foreach (
var prop
in
this._instancePropertyInfos)
260 {
261
if (prop.Name == item.Key)
262
return
true;
263 }
264 }
265
266
return
false;
267 }
268
///
<param name="key"></param>
269
///
<returns></returns>
270
public
bool Contains(
string key,
bool includeInstanceProperties =
false)
271 {
272
bool res = Properties.ContainsKey(key);
273
if (res)
274
return
true;
275
276
if (includeInstanceProperties && _instance !=
null)
277 {
278
foreach (
var prop
in
this._instancePropertyInfos)
279 {
280
if (prop.Name == key)
281
return
true;
282 }
283 }
284
285
return
false;
286 }
287
288 }
289 }