From: <sv...@ca...> - 2005-10-25 17:54:07
|
User: hammett Date: 2005/10/25 01:49 PM Added: /trunk/MonoRail/Castle.MonoRail.Framework/Internal/ ConvertUtils.cs Modified: /trunk/MonoRail/Castle.MonoRail.ActiveRecordSupport.Tests/ ARDataBinderTestCase.cs /trunk/MonoRail/Castle.MonoRail.ActiveRecordSupport/ ARDataBinder.cs, ARSmartDispatchController.cs /trunk/MonoRail/Castle.MonoRail.Framework.Tests/ DataBinderTestCase.cs /trunk/MonoRail/Castle.MonoRail.Framework/ Castle.MonoRail.Framework.csproj, DataBinder.cs, SmartDispatcherController.cs, SmartViewComponent.cs /trunk/MonoRail/Castle.MonoRail.Framework/Attributes/ DataBindAttribute.cs Log: Applied patch from Ahmed Ghandour <agh...@ry...>: - DataBinder refactoring - fix for MR-64 (support for decimals) File Changes: Directory: /trunk/MonoRail/Castle.MonoRail.Framework/Attributes/ ================================================================ File [modified]: DataBindAttribute.cs Delta lines: +12 -0 =================================================================== --- trunk/MonoRail/Castle.MonoRail.Framework/Attributes/DataBindAttribute.cs 2005-10-25 14:05:27 UTC (rev 1218) +++ trunk/MonoRail/Castle.MonoRail.Framework/Attributes/DataBindAttribute.cs 2005-10-25 17:49:09 UTC (rev 1219) @@ -35,6 +35,7 @@ private String prefix = string.Empty; private ParamStore from = ParamStore.Params; private String exclude = String.Empty; + private String allow = String.Empty; private int nestedLevel = 3; public DataBindAttribute() @@ -53,6 +54,17 @@ } /// <summary> + /// Gets or sets the property names to allow. + /// </summary> + /// <value>A comma separated list + /// of property names to allow from databinding.</value> + public String Allow + { + get { return allow; } + set { allow = value; } + } + + /// <summary> /// Gets or sets <see cref="ParamStore"/> used to locate the values used for databinding. /// </summary> /// <value>The ParamStore type. Typically either QueryString, Form, or Params.</value> Directory: /trunk/MonoRail/Castle.MonoRail.ActiveRecordSupport/ =============================================================== File [modified]: ARDataBinder.cs Delta lines: +3 -2 =================================================================== --- trunk/MonoRail/Castle.MonoRail.ActiveRecordSupport/ARDataBinder.cs 2005-10-25 14:05:27 UTC (rev 1218) +++ trunk/MonoRail/Castle.MonoRail.ActiveRecordSupport/ARDataBinder.cs 2005-10-25 17:49:09 UTC (rev 1219) @@ -22,6 +22,7 @@ using Castle.ActiveRecord.Framework.Internal; using Castle.MonoRail.Framework; + using Castle.MonoRail.Framework.Internal; /// <summary> /// Extends DataBinder class with some ActiveRecord specific functionallity @@ -33,7 +34,7 @@ { protected internal static readonly String AutoLoadAttribute = DataBinder.MetadataIdentifier + "autoload"; - public ARDataBinder( IRailsEngineContext context ) : base( context ) + public ARDataBinder() : base() { } @@ -66,7 +67,7 @@ if( propValue != null ) { - object id = DataBinder.Convert(pkModel.Property.PropertyType, propValue, propName, null, null ); + object id = ConvertUtils.Convert(pkModel.Property.PropertyType, propValue, propName, null, null ); instance = SupportingUtils.FindByPK(instanceType, id); } else File [modified]: ARSmartDispatchController.cs Delta lines: +1 -1 =================================================================== --- trunk/MonoRail/Castle.MonoRail.ActiveRecordSupport/ARSmartDispatchController.cs 2005-10-25 14:05:27 UTC (rev 1218) +++ trunk/MonoRail/Castle.MonoRail.ActiveRecordSupport/ARSmartDispatchController.cs 2005-10-25 17:49:09 UTC (rev 1219) @@ -31,7 +31,7 @@ protected override void Initialize() { - binder = new ARDataBinder( Context ); + binder = new ARDataBinder(); } /// <summary> Directory: /trunk/MonoRail/Castle.MonoRail.ActiveRecordSupport.Tests/ ===================================================================== File [modified]: ARDataBinderTestCase.cs Delta lines: +10 -32 =================================================================== --- trunk/MonoRail/Castle.MonoRail.ActiveRecordSupport.Tests/ARDataBinderTestCase.cs 2005-10-25 14:05:27 UTC (rev 1218) +++ trunk/MonoRail/Castle.MonoRail.ActiveRecordSupport.Tests/ARDataBinderTestCase.cs 2005-10-25 17:49:09 UTC (rev 1219) @@ -31,9 +31,9 @@ using TestScaffolding.Model; [TestFixture] - public class ARDataBinderTestCase// : AbstractMRTestCase + public class ARDataBinderTestCase { - private ARDataBinder binder = new ARDataBinder(null); + private ARDataBinder binder = new ARDataBinder(); private NameValueCollection args; private object instance; private SimplePerson person; @@ -56,8 +56,7 @@ args = DataBinderTestCase.ParseNameValueString(data); - instance = binder.BindObject(typeof(SimplePerson), "SimplePerson", - args, null, null, 3, ""); + instance = binder.BindObject(typeof(SimplePerson), "SimplePerson", args); Assert.IsNotNull(instance); person = instance as SimplePerson; @@ -79,8 +78,7 @@ args = DataBinderTestCase.ParseNameValueString(@data); - instance = binder.BindObject(typeof(SimplePerson), "SimplePerson", - args, null, null, 3, ""); + instance = binder.BindObject(typeof(SimplePerson), "SimplePerson", args); Assert.IsNotNull(instance); person = instance as SimplePerson; @@ -100,8 +98,7 @@ try { - instance = binder.BindObject(typeof(SimplePerson), "SimplePerson", - args, null, null, 3, ""); + instance = binder.BindObject(typeof(SimplePerson), "SimplePerson", args); Assert.Fail("Autoload should had thrown an exception, cause pk was missing"); } @@ -124,14 +121,8 @@ try { - instance = binder.BindObject( - typeof(SimplePerson), - "SimplePerson", - args, - null, - null, - 3, - ""); + instance = binder.BindObject( typeof(SimplePerson), "SimplePerson", args); + Assert.Fail("Autoload should had thrown an exception, cause pk value was invalid"); } catch(Castle.ActiveRecord.NotFoundException) @@ -148,14 +139,8 @@ try { - instance = binder.BindObject( - typeof(DisconnectedPerson), - "DisconnectedPerson", - args, - null, - null, - 3, - ""); + instance = binder.BindObject( typeof(DisconnectedPerson), "DisconnectedPerson", args ); + Assert.Fail("Autoload should had thrown an exception, DisconnectedPerson is not an active record class"); } catch(RailsException) @@ -187,14 +172,7 @@ args = DataBinderTestCase.ParseNameValueString(@data); - instance = binder.BindObject( - typeof(SimplePerson[]), - "SimplePerson", - args, - null, - null, - 3, - ""); + instance = binder.BindObject( typeof(SimplePerson[]), "SimplePerson", args ); Assert.IsNotNull(instance); people = instance as SimplePerson[]; Directory: /trunk/MonoRail/Castle.MonoRail.Framework/ ===================================================== File [modified]: Castle.MonoRail.Framework.csproj Delta lines: +5 -0 =================================================================== --- trunk/MonoRail/Castle.MonoRail.Framework/Castle.MonoRail.Framework.csproj 2005-10-25 14:05:27 UTC (rev 1218) +++ trunk/MonoRail/Castle.MonoRail.Framework/Castle.MonoRail.Framework.csproj 2005-10-25 17:49:09 UTC (rev 1219) @@ -374,6 +374,11 @@ BuildAction = "Compile" /> <File + RelPath = "Internal\ConvertUtils.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "Internal\DefaultControllerFactory.cs" SubType = "Code" BuildAction = "Compile" File [modified]: DataBinder.cs Delta lines: +150 -320 =================================================================== --- trunk/MonoRail/Castle.MonoRail.Framework/DataBinder.cs 2005-10-25 14:05:27 UTC (rev 1218) +++ trunk/MonoRail/Castle.MonoRail.Framework/DataBinder.cs 2005-10-25 17:49:09 UTC (rev 1219) @@ -15,13 +15,14 @@ namespace Castle.MonoRail.Framework { using System; - using System.Web; using System.Reflection; using System.Globalization; using System.Collections; using System.Collections.Specialized; using System.Text.RegularExpressions; + using Castle.MonoRail.Framework.Internal; + /// <summary> /// A DataBinder can be used to map properties from /// a NameValueCollection to one or more instance types. @@ -40,75 +41,86 @@ protected internal static readonly BindingFlags PropertiesBindingFlags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - private String root = null; - private IRailsEngineContext context; + #region DataBindContext - #region Constructors - - public DataBinder(IRailsEngineContext context) + /// <summary> + /// This class is used just to minimize the number of params being passed between + /// calls, also to make it easier to make modifications in the future, + /// notice that the recursive nature of the algorithm prevent us from adding all + /// params here unless we implement some kind of stack. + /// </summary> + private class DataBindContext { - this.context = context; + internal NameValueCollection ParamList; + internal IDictionary Files; + internal IList Errors; + internal string [] ExcludedProperties; + internal string [] AllowedProperties; + internal string Root; + + public DataBindContext(String root, NameValueCollection paramList, IDictionary files, + IList errorList, String[] excludedProperties, String[] allowedProperties) + { + Root = root; + ParamList = paramList; + Files = files; + Errors = errorList; + ExcludedProperties = excludedProperties; + AllowedProperties = allowedProperties; + } } - + #endregion - + #region BindObject family - public object BindObject(Type instanceType) + public object BindObject(Type instanceType, String paramPrefix, NameValueCollection paramList) { - return BindObject(instanceType, String.Empty, context.Params, context.Request.Files, null, DefaultNestedLevelsLeft, String.Empty); + return BindObject(instanceType, paramPrefix, paramList, null, null, DefaultNestedLevelsLeft, null); } - public object BindObject(Type instanceType, String paramPrefix, IList errorList, int nestedLevel, String excludedProperties) + public object BindObject(Type instanceType, String paramPrefix, NameValueCollection paramList, + IDictionary files, IList errorList, int nestedLevel, String excludedProperties) { - return BindObject(instanceType, paramPrefix, context.Params, context.Request.Files, errorList, nestedLevel, excludedProperties); + return BindObject(instanceType, paramPrefix, paramList, files, errorList, nestedLevel, excludedProperties, String.Empty ); } - + public object BindObject(Type instanceType, String paramPrefix, NameValueCollection paramList, - IDictionary files, IList errorList, int nestedLevel, String excludedProperties) + IDictionary files, IList errorList, int nestedLevel, String excludedProperties, String allowProperties) { - if (instanceType.IsAbstract || instanceType.IsInterface) return null; - if (root == null) root = instanceType.Name; + String root = GetRoot(instanceType, paramPrefix); + paramPrefix = NormalizeParamPrefix(paramPrefix); - if (ShouldIgnoreElement( paramList, paramPrefix )) return null; + String[] excludedPropertyList = CreateNormalizedList(excludedProperties); + String[] allowPropertyList = CreateNormalizedList(allowProperties); - if (instanceType.IsArray) - { - return BindObjectArrayInstance(instanceType, paramPrefix, paramList, - files, errorList, nestedLevel, excludedProperties); - } - else - { - object instance = CreateInstance(instanceType, paramPrefix, paramList); - - return BindObjectInstance(instance, paramPrefix, paramList, files, - errorList, nestedLevel, excludedProperties); - } + DataBindContext ctx = new DataBindContext(root, paramList, files, errorList, excludedPropertyList, allowPropertyList ); + + return InternalBindObject(instanceType, paramPrefix, nestedLevel, ctx); } + + public object BindObjectInstance(object instance, String paramPrefix, NameValueCollection paramList, + IDictionary files, IList errorList) + { + paramPrefix = NormalizeParamPrefix(paramPrefix); + String root = GetRoot(instance.GetType(), paramPrefix); + + DataBindContext ctx = new DataBindContext(root, paramList, files, errorList, null, null ); + + return InternalRecursiveBindObjectInstance( instance, paramPrefix, DefaultNestedLevelsLeft, ctx ); + } #endregion - #region CreateInstance - protected virtual object CreateInstance( Type instanceType, string paramPrefix, NameValueCollection paramsList ) { return Activator.CreateInstance(instanceType); } - protected virtual object CreateArrayElementInstance( Type instanceType, string paramPrefix, NameValueCollection paramsList ) - { - return CreateInstance( instanceType.GetElementType(), paramPrefix, paramsList ); - } + #region Array Support - #endregion - - #region BindObjectInstance - - public object[] BindObjectArrayInstance(Type instanceType, String paramPrefix, NameValueCollection paramList, - IDictionary files, IList errorList, int nestedLevelsLeft, String excludedProperties) + private object[] InternalBindObjectArray(Type instanceType, String paramPrefix, int nestedLevelsLeft, DataBindContext ctx) { - if(ShouldIgnoreElement( paramList, paramPrefix )) return null; - ArrayList bindArray = new ArrayList(); // check if a count attribute is present, if so we assume the @@ -116,7 +128,7 @@ // param[0], param[1], ... param[count-1] // otherwise we have to find all uniques id for that identifier // which is probably slower but is more flexible - string countBeforeCast = paramList[paramPrefix + CountAttribute ]; + string countBeforeCast = ctx.ParamList[paramPrefix + CountAttribute ]; if( countBeforeCast != null ) { @@ -124,156 +136,105 @@ // if count > paramList.Count that means that there is a problem // in the count variable - if( count > paramList.Count ) count = paramList.Count; + if( count > ctx.ParamList.Count ) count = ctx.ParamList.Count; - for(int i=0; i < count; i++) + for(int prefix=0; prefix < count; prefix++) { - String arrayParamPrefix = paramPrefix + "[" + i + "]"; - - AddArrayInstance(bindArray, instanceType, arrayParamPrefix, - paramList, files, errorList, nestedLevelsLeft, excludedProperties ); + AddArrayElement(bindArray, instanceType, prefix, paramPrefix, nestedLevelsLeft, ctx); } } else { - String[] uniquePrefixes = Grep( paramList.AllKeys, "^" + Regex.Escape( paramPrefix ) + @"\[(.*?)]", 1 ); + String[] uniquePrefixes = Grep( ctx.ParamList.AllKeys, "^" + Regex.Escape( paramPrefix ) + @"\[(.*?)]", 1 ); foreach( string prefix in uniquePrefixes ) - { - String arrayParamPrefix = paramPrefix + "[" + prefix + "]"; - - AddArrayInstance(bindArray, instanceType, arrayParamPrefix, - paramList, files, errorList, nestedLevelsLeft, excludedProperties ); + { + AddArrayElement(bindArray, instanceType, prefix, paramPrefix, nestedLevelsLeft, ctx ); } } return (object[]) bindArray.ToArray( instanceType.GetElementType() ); } - #endregion - - #region BindObjectInstance - - private void AddArrayInstance( ArrayList bindArray, Type instanceType, string arrayParamPrefix, NameValueCollection paramList, IDictionary files, IList errorList, int nestedLevelsLeft, string excludedProperties ) + // Only here so we can support 2 types of loop in the BindObjectArrayInstance + // without duplicating too much code + private void AddArrayElement( ArrayList bindArray, Type instanceType, object arrayPrefix, string paramPrefix, int nestedLevelsLeft, DataBindContext ctx ) { - if( !ShouldIgnoreElement( paramList, arrayParamPrefix ) ) + String arrayParamPrefix = paramPrefix + "[" + arrayPrefix + "]"; + + if( !ShouldIgnoreElement( ctx.ParamList, arrayParamPrefix ) ) { - object instance = CreateArrayElementInstance( - instanceType, arrayParamPrefix, paramList); + object instance = CreateInstance( + instanceType.GetElementType(), arrayParamPrefix, ctx.ParamList); - BindObjectInstance( instance, - arrayParamPrefix, - paramList, - files, - errorList, - nestedLevelsLeft, - excludedProperties ); + InternalRecursiveBindObjectInstance( instance, arrayParamPrefix, nestedLevelsLeft, ctx ); bindArray.Add( instance ); } } - public object BindObjectInstance(object instance, String paramPrefix) - { - paramPrefix = NormalizeParamPrefix(paramPrefix); - - return InternalRecursiveBindObjectInstance(instance, paramPrefix, context.Params, context.Request.Files, - null, DefaultNestedLevelsLeft, string.Empty); - } - - public object BindObjectInstance(object instance, String paramPrefix, NameValueCollection paramList, - IDictionary files, IList errorList) - { - paramPrefix = NormalizeParamPrefix(paramPrefix); - - return InternalRecursiveBindObjectInstance( instance, paramPrefix, paramList, files, errorList, DefaultNestedLevelsLeft, string.Empty ); - } - - public object BindObjectInstance(object instance, String paramPrefix, NameValueCollection paramList, - IDictionary files, IList errorList, int nestedLevel, String excludedProperties) - { - paramPrefix = NormalizeParamPrefix(paramPrefix); - - return InternalRecursiveBindObjectInstance( instance, paramPrefix, paramList, files, errorList, nestedLevel, excludedProperties ); - } - #endregion #region InternalBindObject - - private object InternalBindObject(Type instanceType, String paramPrefix, NameValueCollection paramList, - IDictionary files, IList errorList, int nestedLevelsLeft, string excludedProperties) - { - if (instanceType.IsAbstract || instanceType.IsInterface) return null; - if (root == null) root = instanceType.Name; - object instance = CreateInstance(instanceType, paramPrefix, paramList); - - return InternalRecursiveBindObjectInstance(instance, paramPrefix, paramList, files, - errorList, nestedLevelsLeft, excludedProperties); - } - - private object InternalRecursiveBindObjectInstance(object instance, String paramPrefix, NameValueCollection paramList, - IDictionary files, IList errorList, int nestedLevelsLeft, string excludedProperties) - { - if (--nestedLevelsLeft < 0) + private object InternalBindObject(Type instanceType, String paramPrefix, int nestedLevelsLeft, DataBindContext ctx) + { + if (ShouldIgnoreType(instanceType) || + ShouldIgnoreElement( ctx.ParamList, paramPrefix )) return null; + + if (instanceType.IsArray) { - return instance; + return InternalBindObjectArray(instanceType, paramPrefix, nestedLevelsLeft, ctx); } + else + { + object instance = CreateInstance(instanceType, paramPrefix, ctx.ParamList); + return InternalRecursiveBindObjectInstance(instance, paramPrefix, nestedLevelsLeft, ctx); + } + } - if( ShouldIgnoreElement( paramList, paramPrefix ) ) return null; + private object InternalRecursiveBindObjectInstance(object instance, String paramPrefix, int nestedLevelsLeft, DataBindContext ctx) + { + if (--nestedLevelsLeft < 0) return instance; + if (ShouldIgnoreElement (ctx.ParamList, paramPrefix)) return instance; PropertyInfo[] props = instance.GetType().GetProperties(PropertiesBindingFlags); - String[] excludeList = CreateExcludeList(excludedProperties); - foreach (PropertyInfo prop in props) { - if (!prop.CanWrite || Array.IndexOf(excludeList, prop.Name) != -1) - { - continue; - } - - Type propType = prop.PropertyType; - + if( ShouldIgnoreProperty(prop, ctx) ) continue; + + Type propType = prop.PropertyType; + String paramName = BuildParamName(paramPrefix, prop.Name); try { if ( !IsSimpleProperty(propType) ) { - // if the property is an object, we look if it is already instanciated - object value = prop.GetValue(instance, null); - - String propName = BuildParamName(paramPrefix, prop.Name); - - if( propType.IsArray ) + if( nestedLevelsLeft > 0 ) { - value = BindObjectArrayInstance( - propType, propName, paramList, files, - errorList, nestedLevelsLeft, excludedProperties); - prop.SetValue(instance, value, null); + // if the property is an object, we look if it is already instanciated + object value = prop.GetValue(instance, null); + + // if it's not there, we create it + // Or if is an array + if ( value == null || propType.IsArray ) + { + value = InternalBindObject(propType, paramName, nestedLevelsLeft, ctx); + prop.SetValue(instance, value, null); + } + else // if the object already instanciated, then we use it + { + InternalRecursiveBindObjectInstance(value, paramName, nestedLevelsLeft, ctx); + } } - else if (value == null) // if it's not there, we create it - { - value = InternalBindObject(prop.PropertyType, propName, paramList, files, - errorList, nestedLevelsLeft, excludedProperties); - - prop.SetValue(instance, value, null); - } - else // if the object already instanciated, then we use it - { - InternalRecursiveBindObjectInstance(value, propName, paramList, files, - errorList, nestedLevelsLeft, excludedProperties); - } } else { - String paramName = BuildParamName(paramPrefix, prop.Name); - bool conversionSucceeded; - String[] values = paramList.GetValues(paramName); + String[] values = ctx.ParamList.GetValues(paramName); - object value = Convert(prop.PropertyType, values, paramName, files, context, out conversionSucceeded); + object value = ConvertUtils.Convert(prop.PropertyType, values, paramName, ctx.Files, ctx.ParamList, out conversionSucceeded); // we don't want to set the value if the form param was missing // to avoid loosing existing values in the object instance @@ -285,9 +246,10 @@ } catch (Exception ex) { - if (errorList != null) + if (ctx.Errors != null) { - errorList.Add(new DataBindError(root, BuildParamName(paramPrefix, prop.Name), ex)); + ctx.Errors.Add(new DataBindError( ctx.Root, + (paramPrefix == "") ? paramName : prop.Name, ex )); } else { @@ -303,6 +265,26 @@ #region Helpers + private bool ShouldIgnoreElement( NameValueCollection paramList, string paramPrefix ) + { + return Yes.Equals( paramList.Get(paramPrefix + IgnoreAttribute) ); + } + + private bool ShouldIgnoreProperty( PropertyInfo prop, DataBindContext ctx ) + { + return !prop.CanWrite || + ( ctx.AllowedProperties != null && + Array.IndexOf( ctx.AllowedProperties, prop.Name) == -1 ) || + ( ctx.ExcludedProperties != null && + Array.IndexOf( ctx.ExcludedProperties, prop.Name) != -1 ) ; + } + + private bool ShouldIgnoreType(Type instanceType) + { + return instanceType.IsAbstract || + instanceType.IsInterface; + } + private bool IsSimpleProperty(Type propType) { // When dealing with arrays or lists we want to check @@ -313,36 +295,34 @@ return propType.IsPrimitive || propType.IsEnum || propType == typeof(String) || propType == typeof(Guid) || - propType == typeof(DateTime); + propType == typeof(DateTime) || + propType == typeof(Decimal); } - - private bool ShouldIgnoreElement( NameValueCollection paramList, string paramPrefix ) - { - return Yes.Equals( paramList.Get(paramPrefix + IgnoreAttribute) ); - } - private String[] CreateExcludeList(String excludedProperties) + private string GetRoot( Type type, string prefix ) { - String[] excludeList = excludedProperties.Split(','); - - if (excludedProperties != null) + return (prefix == null) ? type.Name : prefix; + } + + private String[] CreateNormalizedList(String csv) + { + if( csv == null || csv.Trim() == String.Empty ) { - excludeList = excludedProperties.Split(','); - NormalizeExcludeList(excludeList); + return null; } else { - excludeList = new String[] { String.Empty }; + String[] list = csv.Split(','); + NormalizeList(list); + return list; } - - return excludeList; } - private void NormalizeExcludeList(String[] excludeList) + private void NormalizeList(String[] list) { - for(int i=0; i < excludeList.Length; i++) + for(int i=0; i < list.Length; i++) { - excludeList[i] = excludeList[i].Trim(); + list[i] = list[i].Trim(); } } @@ -403,155 +383,5 @@ } #endregion - - #region Convert - - public static object Convert(Type desiredType, String value, String paramName, IDictionary files, IRailsEngineContext context) - { - return Convert(desiredType, new String[] { value }, paramName, files, context); - } - - public static object Convert(Type desiredType, String[] values, String paramName, IDictionary files, IRailsEngineContext context) - { - bool conversionSucceeded; - return Convert(desiredType, values, paramName, files, context, out conversionSucceeded); - } - - private static object Convert(Type desiredType, String[] values, String paramName, IDictionary files, IRailsEngineContext context, out bool conversionSucceeded) - { - String value = null; - - if (values != null && values.Length > 0) - { - value = values[0]; - conversionSucceeded = true; - } - else - { - conversionSucceeded = false; - } - - if (desiredType == typeof(String)) - { - return value; - } - else if (desiredType.IsArray) - { - return values != null ? ConvertToArray(desiredType, values, paramName, files, context) : null; - } - else if (desiredType.IsEnum) - { - if (value == String.Empty || value == null) return null; - - if (!Regex.IsMatch(value.ToString(), @"\D", RegexOptions.Compiled)) - { - object enumValue = System.Convert.ChangeType(value, Enum.GetUnderlyingType(desiredType)); - // optional: test if the specified value is valid within the enum - //if (Enum.IsDefined(desiredType, enumValue)) - // throw or set enumValue = null - return enumValue; - } - - return Enum.Parse(desiredType, value, true); - } - else if (desiredType.IsPrimitive) - { - if (desiredType == typeof(Boolean)) - return (value != null && String.Compare("false", value, true) != 0); - - if (value == String.Empty || value == null) - return null; - - return System.Convert.ChangeType(value, desiredType); - } - else if (desiredType == typeof(Guid)) - { - if (value == null) return Guid.Empty; - return new Guid(value.ToString()); - } - else if (desiredType == typeof(DateTime)) - { - if (value == null) - { - String day = context.Params[paramName + "day"]; - String month = context.Params[paramName + "month"]; - String year = context.Params[paramName + "year"]; - - if (day != null && month != null && year != null) - { - try - { - // we have found a composite date so we - // consider the convertion successful - conversionSucceeded = true; - - return new DateTime( - System.Convert.ToInt32(year), - System.Convert.ToInt32(month), - System.Convert.ToInt32(day)); - } - catch(Exception inner) - { - String message = String.Format("Invalid date (day {0} month {1} year {2}) for {3} ", - day, month, year, paramName); - - throw new ArgumentException(message, inner); - } - } - } - - if (value == null || value == String.Empty) - { - return null; - } - else - { - return DateTime.Parse(value); - } - } - else if (desiredType == typeof(HttpPostedFile)) - { - conversionSucceeded = true; // if we get some files we don't care about the values being null - return files[paramName]; - } - else - { - conversionSucceeded = false; - - if (context != null) - { - String message = String.Format("Ignoring argument '{0}' with value '{1}' " + - "as we don't know how to convert from this value to its type. " + - "desired type = {2}", paramName, value, desiredType); - - context.Trace.Warn(message); - } - } - - return null; - } - - private static object ConvertToArray(Type desiredType, String[] values, String paramName, IDictionary files, IRailsEngineContext context) - { - Type elemType = desiredType.GetElementType(); - - // Fix for mod_mono issue where array values are passed - // as a comma seperated String - if(values.Length == 1 && (values[0].IndexOf(',') > -1)) - { - values = values[0].Split(','); - } - - Array newArray = Array.CreateInstance(elemType, values.Length); - - for(int i=0; i < values.Length; i++) - { - newArray.SetValue(Convert(elemType, new String[] { values[i] }, paramName, files, context), i); - } - - return newArray; - } - - #endregion - } + } } File [modified]: SmartDispatcherController.cs Delta lines: +7 -5 =================================================================== --- trunk/MonoRail/Castle.MonoRail.Framework/SmartDispatcherController.cs 2005-10-25 14:05:27 UTC (rev 1218) +++ trunk/MonoRail/Castle.MonoRail.Framework/SmartDispatcherController.cs 2005-10-25 17:49:09 UTC (rev 1219) @@ -19,6 +19,8 @@ using System.Collections; using System.Collections.Specialized; + using Castle.MonoRail.Framework.Internal; + /// <summary> /// Specialization of <see cref="Controller"/> that tries /// to match the request params to method arguments. @@ -45,7 +47,7 @@ protected override void Initialize() { - binder = new DataBinder( Context ); + binder = new DataBinder(); } protected internal override void CollectActions() @@ -182,11 +184,11 @@ { DataBindAttribute dba = bindAttributes[0] as DataBindAttribute; - args[i] = BindObject( dba.From, param.ParameterType, dba.Prefix, dba.NestedLevel, dba.Exclude ); + args[i] = BindObject( dba.From, param.ParameterType, dba.Prefix, dba.NestedLevel, dba.Exclude, dba.Allow ); } else { - args[i] = DataBinder.Convert( param.ParameterType, allParams.GetValues( paramName ), param.Name, files, Context ); + args[i] = ConvertUtils.Convert( param.ParameterType, allParams.GetValues( paramName ), param.Name, files, allParams ); } } } @@ -206,7 +208,7 @@ return args; } - protected object BindObject(ParamStore from, Type paramType, String prefix, int nestedLevel, String excludedProperties) + protected object BindObject(ParamStore from, Type paramType, String prefix, int nestedLevel, String excludedProperties, String allowedProperties) { NameValueCollection webParams = null; @@ -227,7 +229,7 @@ ArrayList errorList = new ArrayList(); - object instance = binder.BindObject( paramType, prefix, webParams, Context.Request.Files, errorList, nestedLevel, excludedProperties ); + object instance = binder.BindObject( paramType, prefix, webParams, Context.Request.Files, errorList, nestedLevel, excludedProperties, allowedProperties ); boundInstances[instance] = errorList; File [modified]: SmartViewComponent.cs Delta lines: +1 -1 =================================================================== --- trunk/MonoRail/Castle.MonoRail.Framework/SmartViewComponent.cs 2005-10-25 14:05:27 UTC (rev 1218) +++ trunk/MonoRail/Castle.MonoRail.Framework/SmartViewComponent.cs 2005-10-25 17:49:09 UTC (rev 1219) @@ -34,7 +34,7 @@ allParams[ entry.Key.ToString() ] = entry.ToString(); } - DataBinder binder = new DataBinder(RailsContext); + DataBinder binder = new DataBinder(); binder.BindObjectInstance( this, String.Empty, allParams, Request.Files, null ); } Directory: /trunk/MonoRail/Castle.MonoRail.Framework.Tests/ =========================================================== File [modified]: DataBinderTestCase.cs Delta lines: +230 -37 =================================================================== --- trunk/MonoRail/Castle.MonoRail.Framework.Tests/DataBinderTestCase.cs 2005-10-25 14:05:27 UTC (rev 1218) +++ trunk/MonoRail/Castle.MonoRail.Framework.Tests/DataBinderTestCase.cs 2005-10-25 17:49:09 UTC (rev 1219) @@ -31,19 +31,21 @@ { String name = "John"; int age = 32; + decimal assets = (decimal)100000; NameValueCollection args = new NameValueCollection(); args.Add("Person.Name", name); args.Add("Person.Age", age.ToString()); - DataBinder binder = new DataBinder(null); - object instance = binder.BindObject(typeof (Person), "Person", - args, null, null, 3, ""); + args.Add("Person.Assets", assets.ToString() ); + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Person), "Person", args); Assert.IsNotNull(instance); Person person = instance as Person; Assert.IsNotNull(person); Assert.AreEqual(person.Age, age); Assert.AreEqual(person.Name, name); + Assert.AreEqual(person.Assets, assets); } [Test] @@ -55,9 +57,8 @@ args.Add("Name", name); args.Add("Age", age.ToString()); - DataBinder binder = new DataBinder(null); - object instance = binder.BindObject(typeof(Person), "", args, - null, null, 3, ""); + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof(Person), "", args); Assert.IsNotNull(instance); Person person = instance as Person; @@ -74,9 +75,8 @@ NameValueCollection args = new NameValueCollection(); args.Add("Game.Scores", scores); args.Add("Game.Opponents", opponents); - DataBinder binder = new DataBinder(null); - object instance = binder.BindObject(typeof(Game), "Game", args, - null, null, 3, ""); + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof(Game), "Game", args); Assert.IsNotNull(instance); Game game = instance as Game; @@ -99,9 +99,8 @@ "; NameValueCollection args = ParseNameValueString(data); - DataBinder binder = new DataBinder(null); - object instance = binder.BindObject(typeof(Person[]), "Person", - args, null, null, 3, ""); + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof(Person[]), "Person", args); Assert.IsNotNull(instance); Person[] sc = instance as Person[]; @@ -124,9 +123,8 @@ "; NameValueCollection args = ParseNameValueString(data); - DataBinder binder = new DataBinder(null); - object instance = binder.BindObject(typeof (Person[]), "", - args, null, null, 3, ""); + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Person[]), "", args); Assert.IsNotNull(instance); Person[] sc = instance as Person[]; @@ -142,29 +140,26 @@ public void IgnoreAttributeDataBind() { Team[] team = null; - DataBinder binder = new DataBinder(null); + DataBinder binder = new DataBinder(); object instance; NameValueCollection args; foreach (bool useCountAttribute in new bool[] {true, false}) { args = BuildComplexParamList(useCountAttribute); args.Add("Team@ignore", "yes"); - instance = binder.BindObject(typeof (Team[]), "Team", - args, null, null, 3, ""); + instance = binder.BindObject(typeof (Team[]), "Team", args); Assert.IsNull(instance); args.Remove("Team@ignore"); args.Add("Team[0]@ignore", "yes"); - instance = binder.BindObject(typeof(Team[]), - "Team", args, null, null, 3, ""); + instance = binder.BindObject(typeof(Team[]), "Team", args); team = instance as Team[]; Assert.IsNotNull(team); Assert.IsTrue(team.Length == 1); args.Remove("Team[0]@ignore"); args.Add("Team[0].Members@ignore", "yes"); - instance = binder.BindObject(typeof (Team[]), "Team", - args, null, null, 3, ""); + instance = binder.BindObject(typeof (Team[]), "Team", args); team = instance as Team[]; Assert.IsNotNull(team); Assert.IsNull(team[0].Members); @@ -172,6 +167,28 @@ } [Test] + public void NestedLevelArrayDataBind() + { + Team[] team = null; + foreach (bool useCountAttribute in new bool[] {true, false}) + { + NameValueCollection args = BuildComplexParamList(useCountAttribute); + + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Team[]),"Team",args,null,null,1,null); + + Assert.IsNotNull(instance); + team = instance as Team[]; + Assert.IsNotNull(team); + Assert.IsTrue(team[0].Name == "A-Team"); + Assert.IsTrue(team[1].Name == "B-Team"); + Assert.IsNull(team[0].Games); + Assert.IsNull(team[0].Members); + Assert.IsNull(team[1].Members); + } + } + + [Test] public void NestedArrayDataBind() { Team[] team = null; @@ -179,14 +196,12 @@ { NameValueCollection args = BuildComplexParamList(useCountAttribute); - DataBinder binder = new DataBinder(null); - object instance = binder.BindObject(typeof (Team[]),"Team", - args,null,null,3,""); + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Team[]),"Team",args); Assert.IsNotNull(instance); team = instance as Team[]; Assert.IsNotNull(team); - Assert.IsTrue(team.Length == 2); Assert.IsTrue(team[0].Games[0].Scores.Length == 2); Assert.IsTrue(team[0].Games[0].Opponents.Length == 2); Assert.IsTrue(team[0].Games[1].Scores.Length == 3); @@ -198,10 +213,94 @@ Assert.IsTrue(team[0].Members[1].Age == 15); Assert.IsTrue(team[1].Members[0].Name == "Mr. B-White"); Assert.IsTrue(team[1].Members[0].Age == 20); + Assert.IsTrue(team[1].Name == "B-Team"); } } [Test] + public void NestedArrayDataBindWithExcludeList() + { + Team[] team = null; + foreach (bool useCountAttribute in new bool[] {true, false}) + { + NameValueCollection args = BuildComplexParamList(useCountAttribute); + + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Team[]),"Team",args,null,null,3,"Games,Name"); + + Assert.IsNotNull(instance); + team = instance as Team[]; + Assert.IsNotNull(team); + Assert.IsTrue(team.Length == 2); + Assert.IsNull(team[0].Games); + Assert.IsNull(team[0].Name); + Assert.IsTrue(team[0].Members[0].Age == 25); + Assert.IsNull(team[0].Members[1].Name); + Assert.IsTrue(team[0].Members[1].Age == 15); + Assert.IsNull(team[1].Members[0].Name); + Assert.IsTrue(team[1].Members[0].Age == 20); + Assert.IsNull(team[1].Name); + } + } + + [Test] + public void NestedArrayDataBindWithAllowList() + { + Team[] team = null; + foreach (bool useCountAttribute in new bool[] {true, false}) + { + NameValueCollection args = BuildComplexParamList(useCountAttribute); + + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Team[]),"Team",args,null,null,3,null,"Name,Games,Members"); + + Assert.IsNotNull(instance); + team = instance as Team[]; + Assert.IsNotNull(team); + Assert.IsNull(team[0].Games[0].Scores); + Assert.IsNull(team[0].Games[0].Opponents); + Assert.IsNull(team[0].Games[1].Scores); + Assert.IsNull(team[0].Games[1].Opponents); + Assert.IsTrue(team[0].Name == "A-Team"); + Assert.IsTrue(team[0].Members[0].Name == "Mr. White"); + Assert.IsTrue(team[0].Members[0].Age == 0); + Assert.IsTrue(team[0].Members[1].Name == "Mr. Black"); + Assert.IsTrue(team[0].Members[1].Age == 0); + Assert.IsTrue(team[1].Members[0].Name == "Mr. B-White"); + Assert.IsTrue(team[1].Members[0].Age == 0); + Assert.IsTrue(team[1].Name == "B-Team"); + } + } + + [Test] + public void NestedArrayDataBindWithAllowAndExcludeList() + { + Team[] team = null; + foreach (bool useCountAttribute in new bool[] {true, false}) + { + NameValueCollection args = BuildComplexParamList(useCountAttribute); + + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Team[]),"Team",args,null,null,3,"Games","Name,Games,Members"); + + + Assert.IsNotNull(instance); + team = instance as Team[]; + Assert.IsNotNull(team); + // Game pass allowlist but should fail on the exclude + Assert.IsNull(team[0].Games); + Assert.IsTrue(team[0].Name == "A-Team"); + Assert.IsTrue(team[0].Members[0].Name == "Mr. White"); + Assert.IsTrue(team[0].Members[0].Age == 0); + Assert.IsTrue(team[0].Members[1].Name == "Mr. Black"); + Assert.IsTrue(team[0].Members[1].Age == 0); + Assert.IsTrue(team[1].Members[0].Name == "Mr. B-White"); + Assert.IsTrue(team[1].Members[0].Age == 0); + Assert.IsTrue(team[1].Name == "B-Team"); + } + } + + [Test] public void NonNumericIdAttribute() { // Test when count is too big @@ -215,9 +314,8 @@ NameValueCollection args = ParseNameValueString(data); - DataBinder binder = new DataBinder(null); - object instance = binder.BindObject(typeof (Person[]), - "Person", args, null, null, 3, ""); + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Person[]), "Person", args); Assert.IsNotNull(instance); Person[] people = instance as Person[]; @@ -226,6 +324,95 @@ } [Test] + public void SimpleDataBindWithErrors() + { + // Test when count is too big + string data = @" + Person.Name = John + Person.Age = Thirty Two? + "; + + NameValueCollection args = ParseNameValueString(data); + ArrayList errorList = new ArrayList(); + + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Person), "Person", args, null, errorList, 3, null); + + Assert.IsNotNull(instance); + Person person = instance as Person; + Assert.IsNotNull(person); + Assert.IsTrue(person.Name == "John"); + Assert.IsTrue(person.Age == 0); + Assert.IsTrue(errorList.Count == 1); + } + + [Test] + public void SimpleDataBindWithErrorsNoPrefix() + { + // Test when count is too big + string data = @" + Name = John + Age = Thirty Two? + "; + + NameValueCollection args = ParseNameValueString(data); + ArrayList errorList = new ArrayList(); + + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Person), null, args, null, errorList, 3, null); + + Assert.IsNotNull(instance); + Person person = instance as Person; + Assert.IsNotNull(person); + Assert.IsTrue(person.Name == "John"); + Assert.IsTrue(person.Age == 0); + Assert.IsTrue(errorList.Count == 1); + Assert.IsTrue( (errorList[0] as DataBindError).Key.IndexOf("Person") == 0 ); + } + + [Test] + public void ComplexDataBindWithErrors() + { + // Test when count is too big + string data = @" + [0].Games[0].Scores = x,x + [0].Games[0].Opponents = Santos,Cruzeiro + [0].Games[1].Scores = x,x,x + [0].Games[1].Opponents = Santos,Cruzeiro,Guarani + [0].Name = A-Team + [0].Members[0].Name = Mr. White + [0].Members[0].Age = xx + [0].Members[1].Name = Mr. Black + [0].Members[1].Age = xx + [1].Members[0].Name = Mr. B-White + [1].Members[0].Age = xx + [1].Name = B-Team + "; + + NameValueCollection args = ParseNameValueString(data); + ArrayList errorList = new ArrayList(); + + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Team[]), null, args, null, errorList, 3, null); + Assert.IsNotNull(instance); + Team[] team = instance as Team[]; + + Assert.IsNotNull(team); + Assert.IsNull(team[0].Games[0].Scores ); + Assert.IsNull(team[0].Games[1].Scores ); + Assert.IsTrue(team[0].Name == "A-Team"); + Assert.IsTrue(team[1].Name == "B-Team"); + Assert.IsTrue(team[0].Members[0].Name == "Mr. White"); + Assert.IsTrue(team[0].Members[0].Age == 0); + Assert.IsTrue(team[0].Members[1].Name == "Mr. Black"); + Assert.IsTrue(team[0].Members[1].Age == 0); + Assert.IsTrue(team[1].Members[0].Name == "Mr. B-White"); + Assert.IsTrue(team[1].Members[0].Age == 0); + Assert.IsTrue(errorList.Count == 5); + Assert.IsTrue( (errorList[0] as DataBindError).Key.IndexOf("Team") == 0 ); + } + + [Test] public void CountAttribute() { // Test when count is too big @@ -239,9 +426,8 @@ NameValueCollection args = ParseNameValueString(data); - DataBinder binder = new DataBinder(null); - object instance = binder.BindObject(typeof (Person[]), "Person", - args, null, null, 3, ""); + DataBinder binder = new DataBinder(); + object instance = binder.BindObject(typeof (Person[]), "Person", args ); Assert.IsNotNull(instance); Person[] people = instance as Person[]; @@ -249,9 +435,8 @@ Assert.IsTrue(people.Length == 5); args["Person@count"] = "2"; - binder = new DataBinder(null); - instance = binder.BindObject(typeof (Person[]), "Person", - args, null, null, 3, ""); + binder = new DataBinder(); + instance = binder.BindObject(typeof (Person[]), "Person", args ); Assert.IsNotNull(instance); people = instance as Person[]; @@ -288,6 +473,7 @@ Team[0].Members[1].Age = 15 Team[1].Members[0].Name = Mr. B-White Team[1].Members[0].Age = 20 + Team[1].Name = B-Team "; return ParseNameValueString(data); @@ -396,7 +582,8 @@ { private string _name; private Int32 _age; - + private Decimal _assets; + public String Name { get { return _name; } @@ -408,7 +595,13 @@ get { return _age; } set { _age = value; } } + + public Decimal Assets + { + get { return _assets; } + set { _assets = value; } + } } #endregion -} \ No newline at end of file +} Directory: /trunk/MonoRail/Castle.MonoRail.Framework/Internal/ ============================================================== File [added]: ConvertUtils.cs Delta lines: +173 -0 =================================================================== --- trunk/MonoRail/Castle.MonoRail.Framework/Internal/ConvertUtils.cs 2005-10-25 14:05:27 UTC (rev 1218) +++ trunk/MonoRail/Castle.MonoRail.Framework/Internal/ConvertUtils.cs 2005-10-25 17:49:09 UTC (rev 1219) @@ -0,0 +1,173 @@ +// Copyright 2004-2005 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.MonoRail.Framework.Internal +{ + using System; + using System.Collections; + using System.Collections.Specialized; + using System.Text.RegularExpressions; + using System.Web; + + public sealed class ConvertUtils + { + private ConvertUtils() + { + } + + public static object Convert(Type desiredType, String value, String paramName, IDictionary files, NameValueCollection paramList) + { + return Convert(desiredType, new String[] { value }, paramName, files, paramList); + } + + public static object Convert(Type desiredType, String[] values, String paramName, IDictionary files, NameValueCollection paramList) + { + bool conversionSucceeded; + return Convert(desiredType, values, paramName, files, paramList, out conversionSucceeded); + } + + public static object Convert(Type desiredType, String[] values, String paramName, IDictionary files, NameValueCollection paramList, out bool conversionSucceeded) + { + String value = null; + + if (values != null && values.Length > 0) + { + value = values[0]; + conversionSucceeded = true; + } + else + { + conversionSucceeded = false; + } + + if (desiredType == typeof(String)) + { + return value; + } + else if (desiredType.IsArray) + { + return values != null ? ConvertToArray(desiredType, values, paramName, files, paramList) : null; + } + else if (desiredType.IsEnum) + { + if (value == String.Empty || value == null) return null; + + if (!Regex.IsMatch(value.ToString(), @"\D", RegexOptions.Compiled)) + { + object enumValue = System.Convert.ChangeType(value, Enum.GetUnderlyingType(desiredType)); + // optional: test if the specified value is valid within the enum + //if (Enum.IsDefined(desiredType, enumValue)) + // throw or set enumValue = null + return enumValue; + } + + return Enum.Parse(desiredType, value, true); + } + else if (desiredType.IsPrimitive) + { + if (desiredType == typeof(Boolean)) + return (value != null && String.Compare("false", value, true) != 0); + + if (value == String.Empty || value == null) + return null; + + return System.Convert.ChangeType(value, desiredType); + } + else if (desiredType == typeof(Decimal)) + { + if (value == null) return null; + return System.Convert.ToDecimal(value.ToString()); + } + else if (desiredType == typeof(Guid)) + { + if (value == null) return Guid.Empty; + return new Guid(value.ToString()); + } + else if (desiredType == typeof(DateTime)) + { + if (value == null) + { + String day = paramList[paramName + "day"]; + String month = paramList[paramName + "month"]; + String year = paramList[paramName + "year"]; + + if (day != null && month != null && year != null) + { + try + { + // we have found a composite date so we + // consider the convertion successful + conversionSucceeded = true; + + return new DateTime( + System.Convert.ToInt32(year), + System.Convert.ToInt32(month), + System.Convert.ToInt32(day)); + } + catch(Exception inner) + { + String message = String.Format("Invalid date (day {0} month {1} year {2}) for {3} ", + day, month, year, paramName); + + throw new ArgumentException(message, inner); + } + } + } + + if (value == null || value == String.Empty) + { + return null; + } + else + { + return DateTime.Parse(value); + } + } + else if (desiredType == typeof(HttpPostedFile)) + { + conversionSucceeded = true; // if we get some files we don't care about the values being null + return files[paramName]; + } + else + { + String message = String.Format("Cannot conver argument '{0}' with value '{1}' " + + "as we don't know how to convert from this value to its type. " + + "desired type = {2}", paramName, value, desiredType); + + throw new ArgumentException(message); + } + } + + private static object ConvertToArray(Type desiredType, String[] values, String paramName, IDictionary files, NameValueCollection paramList) + { + Type elemType = desiredType.GetElementType(); + + // Fix for mod_mono issue where array values are passed + // as a comma seperated String + if(values.Length == 1 && (values[0].IndexOf(',') > -1)) + { + values = values[0].Split(','); + } + + Array newArray = Array.CreateInstance(elemType, values.Length); + + for(int i=0; i < values.Length; i++) + { + newArray.SetValue(Convert(elemType, new String[] { values[i] }, paramName, files, paramList), i); + } + + return newArray; + } + } +} |