如何确定是否可以在不使用异常的情况下将值分配给DataTable列

本文关键字:情况下 分配 DataTable 异常 是否 何确定 | 更新日期: 2023-09-27 17:57:51

问题

嗨!我想知道是否有可能编写这种C#代码:

try
{
    // I know the dataColumn.DataType but the only way I found
    // to tell whether the value is actually assignable
    // to this column is to assign it and catch the exception
    dataRow[dataColumn] = someStringValue;
}
catch (ArgumentException)
{
    // Now I know, that the value is not applicable to the type
}

而不使用例外。我的用例是我处理大量的行(1000+),我知道这种情况会经常发生,所以我想避免异常处理的开销以获得性能。那么,有可能像使用字典一样检查这个吗?

bool isAssignable = SomeMagicDataHelper.TrySetValue(dataColumn, someStringValue);
if (!isAssignable)
{
    // Now I know, that the value is not applicable to the type
}

我知道这可以在反思的帮助下完成,但我想这样的解决方案会比异常方法更慢。

谢谢!

如何确定是否可以在不使用异常的情况下将值分配给DataTable列

我想我应该这样实现它。它的核心是基于这样一种思想,即列可以是有限的类型列表。这些类型中的大多数提供TryParse,而其他类型(stringbyte[])则更简单。但是,由于不能通过接口调用staticTryParse方法,并且通过反射调用它有点难看和缓慢,所以我决定将其作为生成不同语句的模板来编写。这使它保持快速,并允许您编写一个可维护的模板,而不是一个可怕的代码文件。

将其保存在.tt(T4模板)文件中:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ output extension=".cs" #>
using System;
using System.Data;
namespace MyApp
{
    public static class SomeMagicDataHelper
    {
        public static bool TrySetValue(DataRow dataRow, DataColumn dataColumn, object value)
        {
            try
            {
                if (value == null)
                {
                    if (!dataColumn.AllowDBNull)
                        return false;
                    else
                    {
                        dataRow[dataColumn] = DBNull.Value;
                        return true;
                    }
                }
                // if the types match exactly, a direct assignment will work
                if (value.GetType() == dataColumn.DataType)
                {
                    dataRow[dataColumn] = value;
                    return true;
                }
                // otherwise, we'll do a TryParse
                switch (dataColumn.DataType.FullName)
                {
                    case "<#= typeof(string).FullName #>":
                        dataRow[dataColumn] = value;
                        return true;
                    case "<#= typeof(byte[]).FullName #>":
                        return false;
<# foreach (var type in new[] { typeof(Boolean), typeof(Byte), typeof(Char), typeof(DateTime), typeof(Decimal), typeof(Double), typeof(Guid), typeof(Int16), typeof(Int32), typeof(Int64), typeof(SByte), typeof(Single), typeof(TimeSpan), typeof(UInt16), typeof(UInt32), typeof(UInt64) }) {
#>                    case "<#= type.FullName #>":
                    {
                        <#= type.Name #> tryValue;
                        if (<#= type.Name #>.TryParse(value.ToString(), out tryValue))
                        {
                            dataRow[dataColumn] = tryValue;
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                    }
<# } #>
                }
                // last resort, might throw an exception
                dataRow[dataColumn] = value;
                return true;
            }
            catch (Exception ex)
            {
                // log ex, this shouldn't be a common thing
                return false;
            }
        }
    }
}

我会写一个扩展方法来检查类型是否是有效的数据列类型:

public static bool IsValidType<T>(this DataColumn col, T someStringValue)
{
  return col.Datatype == typeof(T);
}

然后执行:

if (column.IsValidType(someStringValue)
{
  dataRow[dataColumn] = someStringValue    
}