#region " © Copyright 2005-07 to Marcos Meli - http://www.marcosmeli.com.ar" // Errors, suggestions, contributions, send a mail to: marcos@filehelpers.com. #endregion using System; using System.Reflection; using System.Text; namespace FileHelpers { /// Indicates the used for read/write operations. /// See the Complete Attributes List for more clear info and examples of each one. /// Attributes List /// Quick Start Guide /// Examples of Use [AttributeUsage(AttributeTargets.Field)] public sealed class FieldConverterAttribute : Attribute { #region " Constructors " /// Indicates the used for read/write ops. /// The used for the transformations. public FieldConverterAttribute(ConverterKind converter) : this(converter, new string[] {}) { } /// Indicates the used for read/write ops. /// The used for the transformations. /// The first param pased directly to the Converter Constructor. public FieldConverterAttribute(ConverterKind converter, string arg1) : this(converter, new string[] {arg1}) { } /// Indicates the used for read/write ops. /// The used for the transformations. /// The first param pased directly to the Converter Constructor. /// The second param pased directly to the Converter Constructor. public FieldConverterAttribute(ConverterKind converter, string arg1, string arg2) : this(converter, new string[] {arg1, arg2}) { } /// Indicates the used for read/write ops. /// The used for the transformations. /// The first param pased directly to the Converter Constructor. /// The second param pased directly to the Converter Constructor. /// The third param pased directly to the Converter Constructor. public FieldConverterAttribute(ConverterKind converter, string arg1, string arg2, string arg3) : this(converter, new string[] {arg1, arg2, arg3}) { } private FieldConverterAttribute(ConverterKind converter, params string[] args) { Kind = converter; Type convType; switch (converter) { case ConverterKind.Date: convType = typeof (ConvertHelpers.DateTimeConverter); break; case ConverterKind.Byte: convType = typeof (ConvertHelpers.ByteConverter); break; case ConverterKind.SByte: convType = typeof(ConvertHelpers.SByteConverter); break; case ConverterKind.Int16: convType = typeof (ConvertHelpers.Int16Converter); break; case ConverterKind.Int32: convType = typeof (ConvertHelpers.Int32Converter); break; case ConverterKind.Int64: convType = typeof (ConvertHelpers.Int64Converter); break; case ConverterKind.UInt16: convType = typeof(ConvertHelpers.UInt16Converter); break; case ConverterKind.UInt32: convType = typeof(ConvertHelpers.UInt32Converter); break; case ConverterKind.UInt64: convType = typeof(ConvertHelpers.UInt64Converter); break; case ConverterKind.Decimal: convType = typeof (ConvertHelpers.DecimalConverter); break; case ConverterKind.Double: convType = typeof (ConvertHelpers.DoubleConverter); break; case ConverterKind.Single: convType = typeof (ConvertHelpers.SingleConverter); break; case ConverterKind.Boolean: convType = typeof (ConvertHelpers.BooleanConverter); break; default: throw new BadUsageException("Converter '" + converter.ToString() + "' not found, you must specify a valid converter."); } //mType = type; CreateConverter(convType, args); } /// Indicates the used for read/write ops. /// The Type of your custom converter. /// The first param pased directly to the Converter Constructor. public FieldConverterAttribute(Type customConverter, string arg1) : this(customConverter, new string[] {arg1}) { } /// Indicates the used for read/write ops. /// The Type of your custom converter. /// The first param pased directly to the Converter Constructor. /// The second param pased directly to the Converter Constructor. public FieldConverterAttribute(Type customConverter, string arg1, string arg2) : this(customConverter, new string[] {arg1, arg2}) { } /// Indicates the used for read/write ops. /// The Type of your custom converter. /// The first param pased directly to the Converter Constructor. /// The second param pased directly to the Converter Constructor. /// The third param pased directly to the Converter Constructor. public FieldConverterAttribute(Type customConverter, string arg1, string arg2, string arg3) : this(customConverter, new string[] {arg1, arg2, arg3}) { } /// Indicates a custom implementation. /// The Type of your custom converter. /// A list of params pased directly to your converter constructor. public FieldConverterAttribute(Type customConverter, params object[] args) { CreateConverter(customConverter, args); } /// Indicates a custom implementation. /// The Type of your custom converter. public FieldConverterAttribute(Type customConverter) { CreateConverter(customConverter, new object[] {}); } #endregion #region " Converter " internal ConverterBase Converter; internal ConverterKind Kind; #endregion #region " CreateConverter " private void CreateConverter(Type convType, object[] args) { if (typeof (ConverterBase).IsAssignableFrom(convType)) { ConstructorInfo constructor; constructor = convType.GetConstructor(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic, null, ArgsToTypes(args), null); if (constructor == null) { if (args.Length == 0) throw new BadUsageException("Empty constructor for converter: " + convType.Name + " was not found. You must add a constructor without args (can be public or private)"); else throw new BadUsageException("Constructor for converter: " + convType.Name + " with these arguments: (" + ArgsDesc(args) + ") was not found. You must add a constructor with this signature (can be public or private)"); } try { Converter = (ConverterBase) constructor.Invoke(args); } catch (TargetInvocationException ex) { throw ex.InnerException; } } #if ! MINI else if (convType.IsEnum) { Converter = new EnumConverter(convType); } #endif else throw new BadUsageException("The custom converter must inherit from ConverterBase"); } #endregion #region " ArgsToTypes " private Type[] ArgsToTypes(object[] args) { if (args == null) throw new BadUsageException("The args to the constructor can be null, if you not want to pass the ConverterKind."); Type[] res = new Type[args.Length]; for (int i = 0; i < args.Length; i++) { if (args[i] == null) res[i] = typeof (object); else res[i] = args[i].GetType(); } return res; } private string ArgsDesc(object[] args) { string res = DisplayType(args[0]); for(int i = 1; i < args.Length; i++) res += ", " + DisplayType(args[i]); return res; } private string DisplayType(object o) { if (o == null) return "Object"; else return o.GetType().Name; } #endregion internal void ValidateTypes(FieldInfo fi) { bool valid = false; Type fieldType = fi.FieldType; #if NET_2_0 if (fieldType.IsValueType && fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable<>)) { fieldType = fieldType.GetGenericArguments()[0]; } #endif switch (Kind) { case ConverterKind.None: valid = true; break; case ConverterKind.Date: valid = typeof(DateTime) == fieldType; break; case ConverterKind.Byte: case ConverterKind.SByte: case ConverterKind.Int16: case ConverterKind.Int32: case ConverterKind.Int64: case ConverterKind.UInt16: case ConverterKind.UInt32: case ConverterKind.UInt64: case ConverterKind.Decimal: case ConverterKind.Double: case ConverterKind.Single: case ConverterKind.Boolean: valid = Kind.ToString() == fieldType.UnderlyingSystemType.Name; break; } if (valid == false) throw new BadUsageException( "The Converter of the field: '" + fi.Name + "' is wrong. The field is of Type: " + fieldType.Name + " and the converter is for type: " + Kind.ToString()); } } }