如何覆盖.NET类型转换器?

8
我是一个有用的助手,可以进行文本翻译。
我正在开发一种ETL类型的应用程序,该应用程序从csv数据文件中创建实体。其中一个字段 - 布尔字段 - 特别难以处理,因为系统提供了自己的布尔解释,例如true、false、yes、no、1、0甚至-1等。
使用默认类型转换器,大多数测试都失败了:
var b1 = Convert.ChangeType("true", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b2 = Convert.ChangeType("false", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b3 = Convert.ChangeType("True", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b4 = Convert.ChangeType("False", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b5 = Convert.ChangeType("TRUE", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b6 = Convert.ChangeType("FALSE", TypeCode.Boolean, CultureInfo.InvariantCulture);

// All below fail
var b7 = Convert.ChangeType("yes", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b8 = Convert.ChangeType("no", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b9 = Convert.ChangeType("Yes", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b10 = Convert.ChangeType("No", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b11 = Convert.ChangeType("YES", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b12 = Convert.ChangeType("NO", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b13 = Convert.ChangeType("1", TypeCode.Boolean, CultureInfo.InvariantCulture);
var b14 = Convert.ChangeType("0", TypeCode.Boolean, CultureInfo.InvariantCulture);

我想要做的是覆盖默认的System.ComponentModel.BooleanConverter,以便我可以提供自己的解析器来正确处理上述内容。有什么想法吗?
Scott Hanselman的文章涉及创建类型转换器,但我希望覆盖默认的转换器。
供参考,这是我的实体提取器实现。
public static TEntity ExtractEntity<TEntity>(Dictionary<string, string> row)  where TEntity : class
{
    var entity = Activator.CreateInstance<TEntity>();
    var entityType = typeof(TEntity);

    foreach (var info in entityType.GetProperties())
    {
        try
        {
            info.SetValue(
                entity,
                Convert.ChangeType(row[info.Name], info.PropertyType, CultureInfo.InvariantCulture),
                null);
        }
        catch {}
    }

    return entity;
}

基本上,它枚举给定的TEntity,并针对每个公共字段,通过其键获取字典项,并尝试将其转换为字段的底层类型。除了布尔值之外,它运行良好。


2
你可以使用属性注册自定义的bool类型转换器,然后使用TypeDescriptor.GetConverter(info.PropertyType),它将始终返回你的TypeConverter而不是默认值。使用生成的转换器在使用之前将你的值转换为info.PropertyType - Asad Saeeduddin
1个回答

6
感谢 Asad 的帮助,我创建了一个自定义的 TypeConverter
class BoolTypeConverter : TypeConverter
{
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        if (destinationType == typeof (bool))
        {
            return true;
        }
        return base.CanConvertTo(context, destinationType);
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (value is string)
        {
            var s = value as string;
            if (string.IsNullOrEmpty(s))
                return false;
            switch (s.Trim().ToUpper())
            {
                case "TRUE":
                case "YES":
                case "1":
                case "-1":
                    return true;

                default:
                    return false;
            }
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}

并在程序启动时注册:

TypeDescriptor.AddAttributes(typeof(Boolean),
new TypeConverterAttribute(typeof(BoolTypeConverter)));

现在,使用修改后的提取器代码,对于每个属性都使用正确的类型转换器。通常这将是内置转换器之一,但由于已为布尔类型注册了BoolTypeConverter,因此将使用它。
public static TEntity ExtractEntity<TEntity>(Dictionary<string, string> row)  where TEntity : class
{
    var entity = Activator.CreateInstance<TEntity>();
    var entityType = typeof(TEntity);

    foreach (var info in entityType.GetProperties())
    {
        try
        {
            var converter = TypeDescriptor.GetConverter(info.PropertyType);
            if (!converter.CanConvertTo(info.PropertyType)) continue;

            info.SetValue(entity, converter.ConvertTo(row[info.Name], info.PropertyType));
        }
        catch {}
    }

    return entity;
}

由于此答案解决了您的问题,您应该通过点击其旁边的复选标记将其标记为已接受的答案。这样人们一眼就可以看出问题已经得到解决。 - Asad Saeeduddin
太棒了!这会覆盖默认的类型转换吗?还是只是添加另一种转换方式。我希望它只是添加了另一种转换方式。 - C. Tewalt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接