CodeExpression GetExpressionFromString (Type type, string str, MemberInfo member)
{
TypeConverter cvt = GetConverterForMember (member);
if (cvt != null && !SafeCanConvertFrom (typeof (string), cvt))
cvt = null;
object convertedFromAttr = null;
bool preConverted = false;
if (cvt != null && str != null) {
convertedFromAttr = cvt.ConvertFromInvariantString (str);
if (convertedFromAttr != null) {
type = convertedFromAttr.GetType ();
preConverted = true;
}
}
bool wasNullable = false;
Type originalType = type;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
Type[] types = type.GetGenericArguments();
originalType = type;
type = types[0]; // we're interested only in the first type here
wasNullable = true;
}
if (type == typeof (string)) {
object[] urlAttr = member.GetCustomAttributes (typeof (UrlPropertyAttribute), true);
if (urlAttr.Length != 0)
str = HandleUrlProperty ((preConverted && convertedFromAttr is string) ? (string)convertedFromAttr : str, member);
else if (preConverted)
return CreateNullableExpression (originalType,
new CodePrimitiveExpression ((string) convertedFromAttr),
wasNullable);
return CreateNullableExpression (originalType, new CodePrimitiveExpression (str), wasNullable);
} else if (type == typeof (bool)) {
if (preConverted)
return CreateNullableExpression (originalType,
new CodePrimitiveExpression ((bool) convertedFromAttr),
wasNullable);
if (str == null || str == "" || InvariantCompareNoCase (str, "true"))
return CreateNullableExpression (originalType, new CodePrimitiveExpression (true), wasNullable);
else if (InvariantCompareNoCase (str, "false"))
return CreateNullableExpression (originalType, new CodePrimitiveExpression (false), wasNullable);
else if (wasNullable && InvariantCompareNoCase(str, "null"))
return new CodePrimitiveExpression (null);
else
throw new ParseException (currentLocation,
"Value '" + str + "' is not a valid boolean.");
} else if (type == monoTypeType)
type = typeof (System.Type);
if (str == null)
return new CodePrimitiveExpression (null);
if (type.IsPrimitive)
return CreateNullableExpression (originalType,
new CodePrimitiveExpression (
Convert.ChangeType (preConverted ? convertedFromAttr : str,
type, Helpers.InvariantCulture)),
wasNullable);
if (type == typeof (string [])) {
string [] subs;
if (preConverted)
subs = (string[])convertedFromAttr;
else
subs = str.Split (',');
CodeArrayCreateExpression expr = new CodeArrayCreateExpression ();
expr.CreateType = new CodeTypeReference (typeof (string));
foreach (string v in subs)
expr.Initializers.Add (new CodePrimitiveExpression (v.Trim ()));
return CreateNullableExpression (originalType, expr, wasNullable);
}
if (type == typeof (Color)) {
Color c;
if (!preConverted) {
if (colorConverter == null)
colorConverter = TypeDescriptor.GetConverter (typeof (Color));
if (str.Trim().Length == 0) {
CodeTypeReferenceExpression ft = new CodeTypeReferenceExpression (typeof (Color));
return CreateNullableExpression (originalType,
new CodeFieldReferenceExpression (ft, "Empty"),
wasNullable);
}
try {
if (str.IndexOf (',') == -1) {
c = (Color) colorConverter.ConvertFromString (str);
} else {
int [] argb = new int [4];
argb [0] = 255;
string [] parts = str.Split (',');
int length = parts.Length;
if (length < 3)
throw new Exception ();
int basei = (length == 4) ? 0 : 1;
for (int i = length - 1; i >= 0; i--) {
argb [basei + i] = (int) Byte.Parse (parts [i]);
}
c = Color.FromArgb (argb [0], argb [1], argb [2], argb [3]);
}
} catch (Exception e) {
// Hack: "LightGrey" is accepted, but only for ASP.NET, as the
// TypeConverter for Color fails to ConvertFromString.
// Hence this hack...
if (InvariantCompareNoCase ("LightGrey", str)) {
c = Color.LightGray;
} else {
throw new ParseException (currentLocation,
"Color " + str + " is not a valid color.", e);
}
}
} else
c = (Color)convertedFromAttr;
if (c.IsKnownColor) {
CodeFieldReferenceExpression expr = new CodeFieldReferenceExpression ();
if (c.IsSystemColor)
type = typeof (SystemColors);
expr.TargetObject = new CodeTypeReferenceExpression (type);
expr.FieldName = c.Name;
return CreateNullableExpression (originalType, expr, wasNullable);
} else {
CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
m.TargetObject = new CodeTypeReferenceExpression (type);
m.MethodName = "FromArgb";
CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
invoke.Parameters.Add (new CodePrimitiveExpression (c.A));
invoke.Parameters.Add (new CodePrimitiveExpression (c.R));
invoke.Parameters.Add (new CodePrimitiveExpression (c.G));
invoke.Parameters.Add (new CodePrimitiveExpression (c.B));
return CreateNullableExpression (originalType, invoke, wasNullable);
}
}
TypeConverter converter = preConverted ? cvt : wasNullable ? TypeDescriptor.GetConverter (type) : null;
if (converter == null) {
PropertyDescriptor pdesc = TypeDescriptor.GetProperties (member.DeclaringType) [member.Name];
if (pdesc != null)
converter = pdesc.Converter;
else {
Type memberType;
switch (member.MemberType) {
case MemberTypes.Field:
memberType = ((FieldInfo)member).FieldType;
break;
case MemberTypes.Property:
memberType = ((PropertyInfo)member).PropertyType;
break;
default:
memberType = null;
break;
}
if (memberType == null)
return null;
converter = TypeDescriptor.GetConverter (memberType);
}
}
if (preConverted || (converter != null && SafeCanConvertFrom (typeof (string), converter))) {
object value = preConverted ? convertedFromAttr : converter.ConvertFromInvariantString (str);
if (SafeCanConvertTo (typeof (InstanceDescriptor), converter)) {
InstanceDescriptor idesc = (InstanceDescriptor) converter.ConvertTo (value, typeof(InstanceDescriptor));
if (wasNullable)
return CreateNullableExpression (originalType, GenerateInstance (idesc, true),
wasNullable);
CodeExpression instance = GenerateInstance (idesc, true);
if (type.IsPublic)
return new CodeCastExpression (type, instance);
else
return instance;
}
CodeExpression exp = GenerateObjectInstance (value, false);
if (exp != null)
return CreateNullableExpression (originalType, exp, wasNullable);
CodeMethodReferenceExpression m = new CodeMethodReferenceExpression ();
m.TargetObject = new CodeTypeReferenceExpression (typeof (TypeDescriptor));
m.MethodName = "GetConverter";
CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (m);
CodeTypeReference tref = new CodeTypeReference (type);
invoke.Parameters.Add (new CodeTypeOfExpression (tref));
invoke = new CodeMethodInvokeExpression (invoke, "ConvertFrom");
invoke.Parameters.Add (new CodePrimitiveExpression (str));
if (wasNullable)
return CreateNullableExpression (originalType, invoke, wasNullable);
return new CodeCastExpression (type, invoke);
}
Console.WriteLine ("Unknown type: " + type + " value: " + str);
return CreateNullableExpression (originalType, new CodePrimitiveExpression (str), wasNullable);
}