Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Core/DataMemberAccessor.cs @ 5304

Last change on this file since 5304 was 4068, checked in by swagner, 14 years ago

Sorted usings and removed unused usings in entire solution (#1094)

File size: 9.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Reflection;
24using System.Reflection.Emit;
25
26namespace HeuristicLab.Persistence.Core {
27
28  /// <summary>
29  /// Encapsulation and abstraction for access a data member of an object
30  /// regardless of it being a property or field. Additionally a
31  /// default value and an alternate name can be specified.
32  /// </summary>
33  public sealed class DataMemberAccessor {
34
35    #region fields
36
37    /// <summary>
38    /// The function to get the value of the data member.
39    /// </summary>
40    public readonly Func<object, object> Get;
41
42    /// <summary>
43    /// The function to set the value of the data member.
44    /// </summary>
45    public readonly Action<object, object> Set;
46
47    /// <summary>
48    /// The name of the data member.
49    /// </summary>
50    public readonly string Name;
51
52    /// <summary>
53    /// The default value of the data member, can remain <c>null</c>
54    /// if no default value. If left null, this will also leave the
55    /// default value for value types (e.g. 0 for <c>int</c>).
56    /// </summary>
57    public readonly object DefaultValue;
58
59    #endregion
60
61    #region constructors
62
63    /// <summary>
64    /// Create a <see cref="DataMemberAccessor"/> from a FieldInfo or
65    /// PropertyInfo for the give object.
66    /// </summary>
67    /// <param name="memberInfo">The member info.</param>
68    /// <param name="name">The name.</param>
69    /// <param name="defaultvalue">The defaultvalue.</param>
70    public DataMemberAccessor(MemberInfo memberInfo, string name, object defaultvalue) {
71      Get = GenerateGetter(memberInfo);
72      Set = GenerateSetter(memberInfo);
73      Name = name;
74      DefaultValue = defaultvalue;
75    }
76
77    /// <summary>
78    /// Create an empty accessor that just encapsulates an object
79    /// without access.
80    /// </summary>   
81    public DataMemberAccessor() {
82      Name = null;
83      DefaultValue = null;
84      Get = Id;
85    }
86
87    /// <summary>
88    /// Create an empty accessor that just encapsulates an object
89    /// without access.
90    /// </summary>   
91    /// <param name="name">The object's name.</param>
92    public DataMemberAccessor(string name) {
93      Name = name;
94      DefaultValue = null;
95      Get = Id;
96    }
97
98    /// <summary>
99    /// Initializes a new instance of the <see cref="DataMemberAccessor"/> class using the
100    /// getter and setter from an exisiting instance but with a new name and default value.
101    /// </summary>
102    /// <param name="dma">The existing DataMemberAccessor.</param>
103    /// <param name="name">The new name.</param>
104    /// <param name="defaultValue">The new default value.</param>
105    public DataMemberAccessor(DataMemberAccessor dma, string name, object defaultValue) {
106      Get = dma.Get;
107      Set = dma.Set;
108      this.Name = name;
109      this.DefaultValue = defaultValue;
110    }
111
112    #endregion
113
114    #region auxiliary methods
115
116    /// <summary>
117    /// Returns a <see cref="System.String"/> that represents this instance.
118    /// </summary>
119    /// <returns>
120    /// A <see cref="System.String"/> that represents this instance.
121    /// </returns>
122    public override string ToString() {
123      return String.Format("DataMemberAccessor({0}, {1}, {2}, {3})",
124        Name,
125        DefaultValue ?? "<null>",
126        Get.Method, Set.Method);
127    }
128
129    /// <summary>
130    /// The identity function
131    /// </summary>
132    /// <param name="o">An object.</param>
133    /// <returns>its argument o unmodified.</returns>
134    public static object Id(object o) {
135      return o;
136    }
137
138    #endregion
139
140    #region static methods (code generators)
141
142    /// <summary>
143    /// Generate a getter for the given field or property
144    /// </summary>
145    /// <param name="memberInfo">The member info.</param>
146    /// <returns></returns>
147    public static Func<object, object> GenerateGetter(MemberInfo memberInfo) {
148      if (memberInfo.MemberType == MemberTypes.Field) {
149        FieldInfo fieldInfo = (FieldInfo)memberInfo;
150        return GenerateFieldGetter(fieldInfo);
151      } else if (memberInfo.MemberType == MemberTypes.Property) {
152        PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
153        if (!propertyInfo.CanRead || !propertyInfo.CanWrite) {
154          throw new PersistenceException(
155            "Storable properties must implement both a Get and a Set Accessor. ");
156        }
157        return GeneratePropertyGetter(propertyInfo);
158      } else {
159        throw new PersistenceException(
160          "The Storable attribute can only be applied to fields and properties.");
161      }
162    }
163
164    /// <summary>
165    /// Generates a setter for the given field or property.
166    /// </summary>
167    /// <param name="memberInfo">The member info.</param>
168    /// <returns></returns>
169    public static Action<object, object> GenerateSetter(MemberInfo memberInfo) {
170      if (memberInfo.MemberType == MemberTypes.Field) {
171        FieldInfo fieldInfo = (FieldInfo)memberInfo;
172        return GenerateFieldSetter(fieldInfo);
173      } else if (memberInfo.MemberType == MemberTypes.Property) {
174        PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
175        if (!propertyInfo.CanRead || !propertyInfo.CanWrite) {
176          throw new PersistenceException(
177            "Storable properties must implement both a Get and a Set Accessor. ");
178        }
179        return GeneratePropertySetter(propertyInfo);
180      } else {
181        throw new PersistenceException(
182          "The Storable attribute can only be applied to fields and properties.");
183      }
184    }
185
186    /// <summary>
187    /// Generates a dynamically compiled getter to access fields (even private ones).
188    /// </summary>
189    /// <param name="fieldInfo">The field info.</param>
190    /// <returns>A Func&lt;object, object&gt;</returns>
191    public static Func<object, object> GenerateFieldGetter(FieldInfo fieldInfo) {
192      DynamicMethod dm = new DynamicMethod("", typeof(object), new Type[] { typeof(object) }, fieldInfo.DeclaringType, true);
193      ILGenerator ilgen = dm.GetILGenerator();
194      ilgen.Emit(OpCodes.Ldarg_0);
195      ilgen.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
196      ilgen.Emit(OpCodes.Ldfld, fieldInfo);
197      ilgen.Emit(OpCodes.Box, fieldInfo.FieldType);
198      ilgen.Emit(OpCodes.Ret);
199      return (Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>));
200    }
201
202    /// <summary>
203    /// Generates a dynamically compiled sett to access fields (even private ones).
204    /// </summary>
205    /// <param name="fieldInfo">The field info.</param>
206    /// <returns>An Action&lt;object, object%gt;</returns>
207    public static Action<object, object> GenerateFieldSetter(FieldInfo fieldInfo) {
208      DynamicMethod dm = new DynamicMethod("", null, new Type[] { typeof(object), typeof(object) }, fieldInfo.DeclaringType, true);
209      ILGenerator ilgen = dm.GetILGenerator();
210      ilgen.Emit(OpCodes.Ldarg_0);
211      ilgen.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
212      ilgen.Emit(OpCodes.Ldarg_1);
213      ilgen.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
214      ilgen.Emit(OpCodes.Stfld, fieldInfo);
215      ilgen.Emit(OpCodes.Ret);
216      return (Action<object, object>)dm.CreateDelegate(typeof(Action<object, object>));
217    }
218
219    /// <summary>
220    /// Generates a dynamically compiled getter to access properties (even private ones).
221    /// </summary>
222    /// <param name="propertyInfo">The property info.</param>
223    /// <returns>A Func&lt;object, object&gt;</returns>
224    public static Func<object, object> GeneratePropertyGetter(PropertyInfo propertyInfo) {
225      DynamicMethod dm = new DynamicMethod("", typeof(object), new Type[] { typeof(object) }, propertyInfo.DeclaringType, true);
226      ILGenerator ilgen = dm.GetILGenerator();
227      ilgen.Emit(OpCodes.Ldarg_0);
228      ilgen.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
229      ilgen.Emit(OpCodes.Callvirt, propertyInfo.GetGetMethod(true));
230      ilgen.Emit(OpCodes.Box, propertyInfo.PropertyType);
231      ilgen.Emit(OpCodes.Ret);
232      return (Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>));
233    }
234
235    /// <summary>
236    /// Generates a dynamically compiled setter to access properties (even private ones).
237    /// </summary>
238    /// <param name="propertyInfo">The property info.</param>
239    /// <returns>An Action&lt;object, object%gt;</returns>
240    public static Action<object, object> GeneratePropertySetter(PropertyInfo propertyInfo) {
241      DynamicMethod dm = new DynamicMethod("", null, new Type[] { typeof(object), typeof(object) }, propertyInfo.DeclaringType, true);
242      ILGenerator ilgen = dm.GetILGenerator();
243      ilgen.Emit(OpCodes.Ldarg_0);
244      ilgen.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
245      ilgen.Emit(OpCodes.Ldarg_1);
246      ilgen.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
247      ilgen.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod(true));
248      ilgen.Emit(OpCodes.Ret);
249      return (Action<object, object>)dm.CreateDelegate(typeof(Action<object, object>));
250    }
251
252    #endregion
253  }
254
255}
Note: See TracBrowser for help on using the repository browser.