3

Convert.ChangeType("1", typeof(bool)) return a runtime-error

is there any way to override this behavior?

I would like Convert.ChangeType("1", typeof(bool)) returntrue Convert.ChangeType("0", typeof(bool)) return false

UPDATE
reading comments and answers maybe I have not been clear enough

Suppose to have a dictionary of <object,Type> where type is the target type

foreach (var element in dictionary)
{
   object convVal = Convert.ChangeType(element.Key, element.Value);
}

when element.Key is "1" and elemen.Value is bool I would like to get true

Anyone can give me any suggestions to implement a similar behavior

At least something better that this:

 public static class Convert
    {
        public static object ChangeType(object val, Type type)
        {
            if (val is string && type == typeof(bool))
            {

                switch (((string)val).Trim().ToUpper())
                {
                    case "TRUE":
                    case "YES":
                    case "1":
                    case "-1":
                        return true;

                    default:
                        return false;
                }
            }
            return System.Convert.ChangeType(val, type);
        }
    }

Can TypeConverter be the right way?

Please think before to post comments or answers or mark question as duplicated

Ghini Antonio
  • 2,992
  • 2
  • 25
  • 48

5 Answers5

9
bool flag = Convert.ToBoolean(Convert.ToInt32("1"));
Avitus
  • 15,640
  • 6
  • 43
  • 53
  • 1
    Why the Convert.ToInt32? ToBoolean accepts string. https://msdn.microsoft.com/en-us/library/86hw82a3(v=vs.110).aspx – SilentStorm May 18 '17 at 14:20
  • 8
    @SilentStorm read your own link... *"A string that contains the value of either `Boolean.TrueString` or `Boolean.FalseString`"*, so it accepts string as type but it won't process `"1"` into a good result. – grek40 May 18 '17 at 14:44
4

The main problem is, that the conversion of string to bool is supported on the type level, but fails for most string values. This means, that you first have to check for your custom conversion rules before falling back to the default converters. Some of the CanConvert... functions will return true, leading to a runtime exception on actual conversion.

So in order to accept any non-zero number string for true and zero for false, first check numbers separately, then use custom type converters in case they are provided and fall back to the defaults when nothing else is found, you could use the following:

static object CustomConvert(object value, Type targetType)
{
    decimal numericValue;
    if ((targetType == typeof(bool) || targetType == typeof(bool?)) && 
        value is string &&
        decimal.TryParse((string)value, out numericValue))
    {
        return numericValue != 0;
    }
    var valueType = value.GetType();
    var c1 = TypeDescriptor.GetConverter(valueType);
    if (c1.CanConvertTo(targetType)) // this returns false for string->bool
    {
        return c1.ConvertTo(value, targetType);
    }
    var c2 = TypeDescriptor.GetConverter(targetType);
    if (c2.CanConvertFrom(valueType)) // this returns true for string->bool, but will throw for "1"
    {
        return c2.ConvertFrom(value);
    }
    return Convert.ChangeType(value, targetType); // this will throw for "1"
}

Note I didn't check whether it's useful to try Convert.ChangeType after both type converters (From and To) already failed... might as well just throw an exception at this point.

grek40
  • 13,113
  • 1
  • 24
  • 50
  • there is an issue if sting is space or empty on bool type if(targetType == typeof(bool) || targetType == typeof(bool?)) { value = string.IsNullOrWhiteSpace(value?.ToString()) ? 0: Convert.ToInt16(value); } – Power Mouse Mar 15 '21 at 16:37
  • @PowerMouse same problem for input like `"foobar"`. My solution is not a "TryConvert". It only shows how to support a limited set of additional values that are not covered by `Convert.ChangeType`. If you want to support empty strings, go ahead. But I don't see why I should support empty string but not "foobar" and I don't know whether they should mean true or false in a specific context. – grek40 Mar 16 '21 at 07:51
2

what about:

bool x = myString.Equals("1");
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
2

I think best approach for this situation is using equation like below;

string myString = "1";
bool myBool = myString == "1";
Cihan Uygun
  • 2,128
  • 1
  • 16
  • 26
1
Convert.ToBoolean(Convert.ChangeType("1", typeof(uint)));
slfan
  • 8,950
  • 115
  • 65
  • 78
jerry
  • 579
  • 1
  • 4
  • 7