4040
4141namespace SmartStore . ComponentModel
4242{
43- /// <summary>
43+ public enum MemberOptMethod
44+ {
45+ Allow ,
46+ Disallow
47+ }
48+
49+ /// <summary>
4450 /// Class that provides extensible properties and methods to an
4551 /// existing object when cast to dynamic. This
4652 /// dynamic object stores 'extra' properties in a dictionary or
@@ -71,20 +77,29 @@ public class HybridExpando : DynamicObject, IDictionary<string, object>
7177 /// </summary>
7278 private Type _instanceType ;
7379
74- /// <summary>
75- /// String Dictionary that contains the extra dynamic values
76- /// stored on this object/instance
77- /// </summary>
78- /// <remarks>Using PropertyBag to support XML Serialization of the dictionary</remarks>
79- public PropertyBag Properties = new PropertyBag ( ) ;
80+ /// <summary>
81+ /// Adjusted property list for the wrapped instance type after white/black-list members has been applied.
82+ /// </summary>
83+ private IDictionary < string , FastProperty > _instanceProps ;
84+ private readonly static IDictionary < string , FastProperty > EmptyProps = new Dictionary < string , FastProperty > ( ) ;
8085
81- /// <summary>
82- /// This constructor just works off the internal dictionary and any
83- /// public properties of this object.
84- ///
85- /// Note you can subclass Expando.
86- /// </summary>
87- public HybridExpando ( )
86+ /// <summary>
87+ /// String Dictionary that contains the extra dynamic values
88+ /// stored on this object/instance
89+ /// </summary>
90+ /// <remarks>Using PropertyBag to support XML Serialization of the dictionary</remarks>
91+ public PropertyBag Properties = new PropertyBag ( ) ;
92+
93+ private readonly HashSet < string > _optMembers ;
94+ private readonly MemberOptMethod _optMethod ;
95+
96+ /// <summary>
97+ /// This constructor just works off the internal dictionary and any
98+ /// public properties of this object.
99+ ///
100+ /// Note you can subclass Expando.
101+ /// </summary>
102+ public HybridExpando ( )
88103 {
89104 Initialize ( this ) ;
90105 }
@@ -101,12 +116,32 @@ public HybridExpando(object instance)
101116 {
102117 Initialize ( instance ) ;
103118 }
104-
105- protected void Initialize ( object instance )
119+
120+ /// <summary>
121+ /// Allows passing in an existing instance variable to 'extend'
122+ /// along with a list of member names to allow or disallow.
123+ /// </summary>
124+ /// <param name="instance"></param>
125+ public HybridExpando ( object instance , IEnumerable < string > optMembers , MemberOptMethod optMethod )
126+ {
127+ Initialize ( instance ) ;
128+
129+ _optMethod = optMethod ;
130+
131+ if ( optMembers is HashSet < string > h )
132+ {
133+ _optMembers = h ;
134+ }
135+ else
136+ {
137+ _optMembers = new HashSet < string > ( optMembers ) ;
138+ }
139+ }
140+
141+ protected void Initialize ( object instance )
106142 {
107143 _instance = instance ;
108- if ( instance != null )
109- _instanceType = instance . GetType ( ) ;
144+ _instanceType = instance ? . GetType ( ) ;
110145 }
111146
112147 protected object WrappedObject
@@ -119,29 +154,26 @@ public override IEnumerable<string> GetDynamicMemberNames()
119154 foreach ( var kvp in this . Properties . Keys )
120155 {
121156 yield return kvp ;
122- }
157+ }
123158
124- if ( _instance != null )
159+ foreach ( var kvp in GetInstanceProperties ( ) )
125160 {
126- foreach ( var kvp in FastProperty . GetProperties ( _instance ) )
161+ if ( ! this . Properties . ContainsKey ( kvp . Key ) )
127162 {
128- if ( ! this . Properties . ContainsKey ( kvp . Key ) )
129- {
130- yield return kvp . Key ;
131- }
163+ yield return kvp . Key ;
132164 }
133165 }
134166 }
135167
136168
137- /// <summary>
138- /// Try to retrieve a member by name first from instance properties
139- /// followed by the collection entries.
140- /// </summary>
141- /// <param name="binder"></param>
142- /// <param name="result"></param>
143- /// <returns></returns>
144- public override bool TryGetMember ( GetMemberBinder binder , out object result )
169+ /// <summary>
170+ /// Try to retrieve a member by name first from instance properties
171+ /// followed by the collection entries.
172+ /// </summary>
173+ /// <param name="binder"></param>
174+ /// <param name="result"></param>
175+ /// <returns></returns>
176+ public override bool TryGetMember ( GetMemberBinder binder , out object result )
145177 {
146178 return TryGetMemberCore ( binder . Name , out result ) ;
147179 }
@@ -259,8 +291,7 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, o
259291 /// <returns></returns>
260292 protected bool GetProperty ( object instance , string name , out object result )
261293 {
262- var fastProp = _instanceType != null ? FastProperty . GetProperty ( _instanceType , name , PropertyCachingStrategy . EagerCached ) : null ;
263- if ( fastProp != null )
294+ if ( GetInstanceProperties ( ) . TryGetValue ( name , out var fastProp ) )
264295 {
265296 result = fastProp . GetValue ( instance ?? this ) ;
266297 return true ;
@@ -279,12 +310,11 @@ protected bool GetProperty(object instance, string name, out object result)
279310 /// <returns></returns>
280311 protected bool SetProperty ( object instance , string name , object value )
281312 {
282- var fastProp = _instanceType != null ? FastProperty . GetProperty ( _instanceType , name , PropertyCachingStrategy . EagerCached ) : null ;
283- if ( fastProp != null )
313+ if ( GetInstanceProperties ( ) . TryGetValue ( name , out var fastProp ) )
284314 {
285315 fastProp . SetValue ( instance ?? this , value ) ;
286316 return true ;
287- }
317+ }
288318
289319 return false ;
290320 }
@@ -361,9 +391,9 @@ public IEnumerable<KeyValuePair<string, object>> GetProperties(bool includeInsta
361391 yield return kvp ;
362392 }
363393
364- if ( includeInstanceProperties && _instance != null )
394+ if ( includeInstanceProperties )
365395 {
366- foreach ( var prop in FastProperty . GetProperties ( _instance ) . Values )
396+ foreach ( var prop in GetInstanceProperties ( ) . Values )
367397 {
368398 if ( ! this . Properties . ContainsKey ( prop . Name ) )
369399 {
@@ -373,6 +403,30 @@ public IEnumerable<KeyValuePair<string, object>> GetProperties(bool includeInsta
373403 }
374404 }
375405
406+ private IDictionary < string , FastProperty > GetInstanceProperties ( )
407+ {
408+ if ( _instance == null )
409+ {
410+ return EmptyProps ;
411+ }
412+
413+ if ( _instanceProps == null )
414+ {
415+ var props = FastProperty . GetProperties ( _instance ) as IDictionary < string , FastProperty > ;
416+
417+ if ( _optMembers != null )
418+ {
419+ props = props
420+ . Where ( x => _optMethod == MemberOptMethod . Allow ? _optMembers . Contains ( x . Key ) : ! _optMembers . Contains ( x . Key ) )
421+ . ToDictionary ( x => x . Key , x => x . Value ) ;
422+ }
423+
424+ _instanceProps = props ;
425+ }
426+
427+ return _instanceProps ;
428+ }
429+
376430 /// <summary>
377431 /// Checks whether a property exists in the Property collection
378432 /// or as a property on the instance
@@ -398,10 +452,10 @@ public bool Contains(string propertyName, bool includeInstanceProperties = false
398452 return true ;
399453 }
400454
401- if ( includeInstanceProperties && _instance != null )
455+ if ( includeInstanceProperties )
402456 {
403- return FastProperty . GetProperties ( _instance ) . ContainsKey ( propertyName ) ;
404- }
457+ return GetInstanceProperties ( ) . ContainsKey ( propertyName ) ;
458+ }
405459
406460 return false ;
407461 }
0 commit comments