关于C#中对象和字典间相互转换的说明

一、对象转换为字典:

/// <summary>
/// 转换对象为字典
/// </summary>
/// <param name="obj">要转换的对象</param>
/// <param name="members">需要转换的成员</param>
/// <param name="ignoreMembers">忽略转换的成员</param>
/// <returns>返回字典</returns>
public virtual Dictionary<string, object> ConvertDictionary(object obj, string[] members, string[] ignoreMembers)
{
    // 创建目标字典
    Dictionary<string, object> dictionary = new Dictionary<string, object>();
    // 获取对象类型
    Type type = obj.GetType();
    // 获取成员字段
    FieldInfo[] fieldInfos = type.GetFields();
    // 遍历成员字段,添加要转换的成员字段到字典中
    foreach (FieldInfo fieldInfo in fieldInfos)
    {
        // 获取当前字段名
        string name = fieldInfo.Name;
        // 判断当前字段是否需要转换
        if ((members == null || members.Length <= 0 || members.Contains("*") || members.Contains(name)) && (ignoreMembers == null || ignoreMembers.Length <= 0 || (!ignoreMembers.Contains("*") && !ignoreMembers.Contains(name))))
        {
            // 判断当前字段是否是公开的
            if (fieldInfo.IsPublic)
            {
                // 判断当前字段是否是静态的
                if (fieldInfo.IsStatic)
                {
                    // 获取成员字段的静态值并设置到字典中
                    dictionary[name] = fieldInfo.GetValue(null);
                }
                else
                {
                    // 获取成员字段的实例值并设置到字典中
                    dictionary[name] = fieldInfo.GetValue(obj);
                }
            }
        }
    }
    // 获取成员属性
    PropertyInfo[] propertyInfos = type.GetProperties();
    // 遍历成员属性,添加要转换的成员属性到字典中
    foreach (PropertyInfo propertyInfo in propertyInfos)
    {
        // 获取当前属性名
        string name = propertyInfo.Name;
        // 判断当前属性是否需要转换
        if ((members == null || members.Length <= 0 || members.Contains("*") || members.Contains(name)) && (ignoreMembers == null || ignoreMembers.Length <= 0 || (!ignoreMembers.Contains("*") && !ignoreMembers.Contains(name))))
        {
            // 判断当前属性是否可读的并且是简单的类型
            if (propertyInfo.CanRead)
            {
                // 获取当前属性的GET访问器
                MethodInfo methodInfo = propertyInfo.GetGetMethod();
                // 判断当前属性的GET访问器是否是公开的
                if (methodInfo.IsPublic)
                {
                    // 判断当前属性的GET访问器是否是静态的
                    if (methodInfo.IsStatic)
                    {
                        // 获取成员属性的静态值并设置到字典中
                        dictionary[name] = propertyInfo.GetValue(null, null);
                    }
                    else
                    {
                        // 获取成员属性的实例值并设置到字典中
                        dictionary[name] = propertyInfo.GetValue(obj, null);
                    }
                }
            }
        }
    }
    // 返回字典
    return dictionary;
}

二、字典转换为对象:

/// <summary>
/// 转换字典为对象
/// </summary>
/// <param name="type">对象类型</param>
/// <param name="dictionary">要转换的字典</param>
/// <param name="members">需要转换的成员</param>
/// <param name="ignoreMembers">忽略转换的成员</param>
/// <returns>返回对象</returns>
public virtual object ConvertDictionary(Type type, Dictionary<string, object> dictionary, string[] members, string[] ignoreMembers)
{
    // 创建目标对象
    object obj = Activator.CreateInstance(type);
    // 遍历字典,添加要转换的数据到对象成员中
    foreach (KeyValuePair<string, object> item in dictionary)
    {
        // 获取成员名称
        string name = item.Key;
        // 判断当前成员是否需要转换
        if ((members == null || members.Length <= 0 || members.Contains("*") || members.Contains(name)) && (ignoreMembers == null || ignoreMembers.Length <= 0 || (!ignoreMembers.Contains("*") && !ignoreMembers.Contains(name))))
        {
            // 获取当前成员名称对应的数据
            object value = item.Value;
            // 根据当前成员名称获取成员属性
            PropertyInfo propertyInfo = type.GetProperty(name);
            // 判断是否有对应名称的成员属性
            if (propertyInfo == null)
            {
                // 根据当前列名获取成员字段
                FieldInfo fieldInfo = type.GetField(name);
                // 判断成员字段是否存在并且是否是公开可写的
                if (fieldInfo != null && fieldInfo.IsPublic && !fieldInfo.IsLiteral && !fieldInfo.IsInitOnly)
                {
                    // 根据成员字段类型转换数据类型
                    value = this.ConvertType(value, fieldInfo.FieldType);
                    // 判断数据转换是否成功
                    if (value != null)
                    {
                        // 判断成员字段是否是静态的
                        if (fieldInfo.IsStatic)
                        {
                            // 设置成员字段的静态值
                            fieldInfo.SetValue(null, value);
                        }
                        else
                        {
                            // 设置成员字段的实例值
                            fieldInfo.SetValue(obj, value);
                        }
                    }
                }
            }
            else
            {
                // 判断成员属性是否可写
                if (propertyInfo.CanWrite)
                {
                    // 获取成员属性的SET访问器
                    MethodInfo methodInfo = propertyInfo.GetSetMethod();
                    // 判断成员属性的SET访问器是否是公开的
                    if (methodInfo.IsPublic)
                    {
                        // 根据成员属性类型转换数据类型
                        value = this.ConvertType(value, propertyInfo.PropertyType);
                        // 判断数据转换是否成功
                        if (value != null)
                        {
                            // 判断成员属性的SET访问器是否是静态的
                            if (methodInfo.IsStatic)
                            {
                                // 设置成员属性的静态值
                                propertyInfo.SetValue(null, value, null);
                            }
                            else
                            {
                                // 设置成员属性的实例值
                                propertyInfo.SetValue(obj, value, null);
                            }
                        }
                    }
                }
            }
        }
    }
    // 返回目标对象
    return obj;
}

关于C#中Array和DataTable间相互转换的说明

一、将Array转换为DataTable:

/// <summary>
/// 转换对象数组为数据表
/// </summary>
/// <param name="objs">对象数组</param>
/// <param name="members">需要转换的成员</param>
/// <param name="ignoreMembers">忽略转换的成员</param>
/// <returns>返回数据表</returns>
public virtual DataTable ConvertTable(object[] objs, string[] members, string[] ignoreMembers)
{
    // 创建目标数据表
    DataTable dataTable = new DataTable();
    // 获取对象数组元素类型
    Type type = objs.GetType().GetElementType();
    // 创建要转换的对象成员字典
    Dictionary<string, MemberInfo> memberInfos = new Dictionary<string, MemberInfo>();
    // 获取成员字段
    FieldInfo[] fieldInfos = type.GetFields();
    // 遍历成员字段,添加要转换的成员字段到字典中
    foreach (FieldInfo fieldInfo in fieldInfos)
    {
        // 获取当前字段名
        string name = fieldInfo.Name;
        // 判断当前字段是否需要转换
        if ((members == null || members.Length <= 0 || members.Contains("*") || members.Contains(name)) && (ignoreMembers == null || ignoreMembers.Length <= 0 || (!ignoreMembers.Contains("*") && !ignoreMembers.Contains(name))))
        {
            // 判断当前字段是否是公开的
            if (fieldInfo.IsPublic)
            {
                // 添加要转换的成员字段
                memberInfos[name] = fieldInfo;
            }
        }
    }
    // 获取成员属性
    PropertyInfo[] propertyInfos = type.GetProperties();
    // 遍历成员属性,添加要转换的成员属性到字典中
    foreach (PropertyInfo propertyInfo in propertyInfos)
    {
        // 获取当前属性名
        string name = propertyInfo.Name;
        // 判断当前属性是否需要转换
        if ((members == null || members.Length <= 0 || members.Contains("*") || members.Contains(name)) && (ignoreMembers == null || ignoreMembers.Length <= 0 || (!ignoreMembers.Contains("*") && !ignoreMembers.Contains(name))))
        {
            // 判断当前属性是否可读
            if (propertyInfo.CanRead)
            {
                // 获取当前属性的GET访问器
                MethodInfo methodInfo = propertyInfo.GetGetMethod();
                // 判断当前属性的GET访问器是否是公开的
                if (methodInfo.IsPublic)
                {
                    // 添加要转换的成员属性
                    memberInfos[name] = propertyInfo;
                }
            }
        }
    }
    // 遍历要转换的对象成员字典,添加数据列
    foreach (KeyValuePair<string, MemberInfo> item in memberInfos)
    {
        // 添加数据列
        DataColumn dataColumn = dataTable.Columns.Add(item.Key);
        // 定义数据列数据类型
        Type dataType = typeof(string);
        // 获取对象成员
        MemberInfo membeInfo = item.Value;
        // 判断对象成员是否是属性
        if (membeInfo is PropertyInfo)
        {
            // 获取成员属性
            PropertyInfo propertyInfo = membeInfo as PropertyInfo;
            // 设置数据列类型
            dataType = propertyInfo.PropertyType;
        }
        else
        {
            // 获取成员字段
            FieldInfo fieldInfo = membeInfo as FieldInfo;
            // 设置数据列类型
            dataType = fieldInfo.FieldType;
        }
        // 判断数据类型是否是可空的泛型值类型
        if (dataType.IsGenericType && dataType.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            // 取出可空泛型值类型中的基础值类型
            dataType = Nullable.GetUnderlyingType(dataType);
        }
        // 设置数据列数据类型
        dataColumn.DataType = dataType;
    }
    // 遍历对象数组,转换对象为数据行
    foreach (object obj in objs)
    {
        // 创建数据行数据链表
        List<object> values = new List<object>();
        // 遍历要转换的对象成员字典,转换成员数据
        foreach (KeyValuePair<string, MemberInfo> item in memberInfos)
        {
            // 定义成员数据
            object value = null;
            // 获取对象成员
            MemberInfo membeInfo = item.Value;
            // 判断对象成员是否是属性
            if (membeInfo is PropertyInfo)
            {
                // 获取成员属性
                PropertyInfo propertyInfo = membeInfo as PropertyInfo;
                // 获取当前成员属性的GET访问器
                MethodInfo methodInfo = propertyInfo.GetGetMethod();
                // 判断当前成员属性的GET访问器是否是静态的
                if (methodInfo.IsStatic)
                {
                    // 获取成员属性的静态值
                    value = propertyInfo.GetValue(null, null);
                }
                else
                {
                    // 获取成员属性的实例值
                    value = propertyInfo.GetValue(obj, null);
                }
            }
            else
            {
                // 获取成员字段
                FieldInfo fieldInfo = membeInfo as FieldInfo;
                // 判断当前成员字段是否是静态的
                if (fieldInfo.IsStatic)
                {
                    // 获取成员字段的静态值
                    value = fieldInfo.GetValue(null);
                }
                else
                {
                    // 获取成员字段的实例值
                    value = fieldInfo.GetValue(obj);
                }
            }
            // 添加成员数据到数据行数据链表中
            values.Add(value);
        }
        // 添加数据行
        dataTable.Rows.Add(values.ToArray());
    }
    // 返回数据表
    return dataTable;
}

二、将DataTable转换为Array:

/// <summary>
/// 转换数据表为对象数组
/// </summary>
/// <param name="type">对象类型</param>
/// <param name="dataTable">数据表</param>
/// <param name="members">需要转换的成员</param>
/// <param name="ignoreMembers">忽略转换的成员</param>
/// <returns>返回对象数组</returns>
public virtual object[] ConvertTable(Type type, DataTable dataTable, string[] members, string[] ignoreMembers)
{
    // 创建目标对象数组
    object[] objs = Array.CreateInstance(type, dataTable.Rows.Count) as object[];
    // 创建要转换的对象成员字典
    Dictionary<string, MemberInfo> memberInfos = new Dictionary<string, MemberInfo>();
    // 遍历数据表中所有列,添加要转换的对象成员到字典中
    foreach (DataColumn dataColumn in dataTable.Columns)
    {
        // 获取列名
        string name = dataColumn.ColumnName;
        // 判断当前列是否需要转换
        if ((members == null || members.Length <= 0 || members.Contains("*") || members.Contains(name)) && (ignoreMembers == null || ignoreMembers.Length <= 0 || (!ignoreMembers.Contains("*") && !ignoreMembers.Contains(name))))
        {
            // 根据当前列名获取成员属性
            PropertyInfo propertyInfo = type.GetProperty(name);
            // 判断是否有对应名称的成员属性
            if (propertyInfo == null)
            {
                // 根据当前列名获取成员字段
                FieldInfo fieldInfo = type.GetField(name);
                // 判断成员字段是否存在并且是否是公开可写的
                if (fieldInfo != null && fieldInfo.IsPublic && !fieldInfo.IsLiteral && !fieldInfo.IsInitOnly)
                {
                    // 添加要转换的对象成员
                    memberInfos[name] = fieldInfo;
                }
            }
            else
            {
                // 判断成员属性是否可写
                if (propertyInfo.CanWrite)
                {
                    // 获取成员属性的SET访问器
                    MethodInfo methodInfo = propertyInfo.GetSetMethod();
                    // 判断成员属性的SET访问器是否是公开的
                    if (methodInfo.IsPublic)
                    {
                        // 添加要转换的对象成员
                        memberInfos[name] = propertyInfo;
                    }
                }
            }
        }
    }
    // 遍历转换数据表中的所有行
    for (int i = 0, length = dataTable.Rows.Count; i < length; i++)
    {
        // 获取对应索引的数据行
        DataRow dataRow = dataTable.Rows[i];
        // 根据对象类型创建目标对象
        object obj = Activator.CreateInstance(type);
        // 遍历要转换的对象成员字典,转换成员数据
        foreach (KeyValuePair<string, MemberInfo> item in memberInfos)
        {
            // 获取当前行对应当前列的数据
            object value = dataRow[item.Key];
            // 获取对象成员
            MemberInfo membeInfo = item.Value;
            // 判断对象成员是否是属性
            if (membeInfo is PropertyInfo)
            {
                // 获取成员属性
                PropertyInfo propertyInfo = membeInfo as PropertyInfo;
                // 根据成员属性类型转换数据类型
                value = this.ConvertType(value, propertyInfo.PropertyType);
                // 判断数据转换是否成功
                if (value != null)
                {
                    // 获取成员属性的SET访问器
                    MethodInfo methodInfo = propertyInfo.GetSetMethod();
                    // 判断成员属性的SET访问器是否是静态的
                    if (methodInfo.IsStatic)
                    {
                        // 设置成员属性的静态值
                        propertyInfo.SetValue(null, value, null);
                    }
                    else
                    {
                        // 设置成员属性的实例值
                        propertyInfo.SetValue(obj, value, null);
                    }
                }
            }
            else
            {
                // 获取成员字段
                FieldInfo fieldInfo = membeInfo as FieldInfo;
                // 根据成员字段类型转换数据类型
                value = this.ConvertType(value, fieldInfo.FieldType);
                // 判断数据转换是否成功
                if (value != null)
                {
                    // 判断成员字段是否是静态的
                    if (fieldInfo.IsStatic)
                    {
                        // 设置成员字段的静态值
                        fieldInfo.SetValue(null, value);
                    }
                    else
                    {
                        // 设置成员字段的实例值
                        fieldInfo.SetValue(obj, value);
                    }
                }
            }
        }
        // 设置目标对象到对象数组中
        objs[i] = obj;
    }
    // 返回目标对象数组
    return objs;
}

关于C#中通用对象成员复制的说明

/// <summary>
/// 复制对象成员
/// </summary>
/// <param name="source">被复制的对象</param>
/// <param name="target">要复制的对象</param>
/// <param name="members">需要复制的成员</param>
/// <param name="ignoreMembers">忽略复制的成员</param>
public virtual void CopyMembers(object source, object target, string[] members, string[] ignoreMembers)
{
    // 获取对象类型
    Type type = source.GetType();
    // 获取对象属性信息
    PropertyInfo[] propertyInfos = type.GetProperties();
    // 遍历复制对象属性
    foreach (PropertyInfo propertyInfo in propertyInfos)
    {
        // 获取当前属性名
        string name = propertyInfo.Name;
        // 判断当前属性是否需要进行复制
        if ((members == null || members.Length <= 0 || members.Contains("*") || members.Contains(name)) && (ignoreMembers == null || ignoreMembers.Length <= 0 || (!ignoreMembers.Contains("*") && !ignoreMembers.Contains(name))))
        {
            // 判断当前属性是否可读写
            if (propertyInfo.CanRead && propertyInfo.CanWrite)
            {
                // 获取当前属性的GET访问器
                MethodInfo getMethodInfo = propertyInfo.GetSetMethod();
                // 获取当前属性的SET访问器
                MethodInfo setMethodInfo = propertyInfo.GetSetMethod();
                // 判断GET/SET访问器是否是公开的
                if (getMethodInfo.IsPublic && setMethodInfo.IsPublic)
                {
                    object value;
                    // 判断GET访问器是否是静态访问器
                    if (getMethodInfo.IsStatic)
                    {
                        // 获取当前属性的静态值
                        value = propertyInfo.GetValue(null, null);
                    }
                    else
                    {
                        // 获取被复制对象当前属性的实例值
                        value = propertyInfo.GetValue(source, null);
                    }
                    // 判断SET访问器是否是静态访问器
                    if (setMethodInfo.IsStatic)
                    {
                        // 设置当前属性的静态值
                        propertyInfo.SetValue(null, value, null);
                    }
                    else
                    {
                        // 设置要复制对象当前属性的实例值
                        propertyInfo.SetValue(target, value, null);
                    }
                }
            }
        }
    }
    // 获取对象字段信息
    FieldInfo[] fieldInfos = type.GetFields();
    // 遍历复制对象字段
    foreach (FieldInfo fieldInfo in fieldInfos)
    {
        // 获取当前字段名
        string name = fieldInfo.Name;
        // 判断当前字段是否需要进行复制
        if ((members == null || members.Length <= 0 || members.Contains("*") || members.Contains(name)) && (ignoreMembers == null || ignoreMembers.Length <= 0 || (!ignoreMembers.Contains("*") && !ignoreMembers.Contains(name))))
        {
            // 判断当前字段是否是公开可写的
            if (fieldInfo.IsPublic && !fieldInfo.IsLiteral && !fieldInfo.IsInitOnly)
            {
                // 判断当前字段是否是静态的
                if (fieldInfo.IsStatic)
                {
                    // 获取当前字段的静态值
                    object value = fieldInfo.GetValue(null);
                    // 设置当前字段的静态值
                    fieldInfo.SetValue(null, value);
                }
                else
                {
                    // 获取被复制对象当前字段的实例值
                    object value = fieldInfo.GetValue(source);
                    // 设置要复制对象当前字段的实例值
                    fieldInfo.SetValue(target, value);
                }
            }
        }
    }
}

关于C#中通用对象类型转换的说明

/// <summary>
/// 转换对象类型
/// </summary>
/// <param name="targetType">转换后类型</param>
/// <param name="source">要转换的对象</param>
/// <returns>返回转换后的对象</returns>
public virtual object ConvertType(object source, Type targetType)
{
    // 判断原始对象是否为空或者目标类型是否可以由原始对象直接转换
    if (source == null || targetType.IsAssignableFrom(source.GetType()))
    {
        // 返回原始对象
        return source;
    }
    else
    {
        // 判断原始对象是否是空字符串
        if (source is string && string.IsNullOrWhiteSpace(source as string))
        {
            // 无法转换,返回默认值
            return targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
        }
        else
        {
            // 判断目标对象是否是可空的泛型值类型
            if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                // 取出可空泛型值类型中的基础值类型
                targetType = Nullable.GetUnderlyingType(targetType);
            }
            // 判断目标对象是否是枚举
            if (targetType.IsEnum)
            {
                // 转换并返回目标对象枚举
                return Enum.Parse(targetType, source.ToString());
            }
            else
            {
                // 判断原始对象是否是集合
                if (source is ICollection)
                {
                    // 将原始对象转换为集合对象
                    ICollection collection = source as ICollection;
                    // 判断目标类型是否是数组
                    if (targetType.IsArray)
                    {
                        // 根据目标类型和原始集合对象的长度创建目标对象数组
                        Array target = Activator.CreateInstance(targetType, collection.Count) as Array;
                        // 获取目标对象数组的元素类型
                        Type elementType = targetType.GetElementType();
                        // 遍历并转换原始集合对象数据到目标对象数组中
                        int i = 0;
                        foreach (var item in collection)
                        {
                            // 将当前原始数据项转换为目标元素类型并设置到对应的目标对象数组中
                            target.SetValue(this.ConvertType(item, elementType), i);
                            i++;
                        }
                        // 返回目标对象数组
                        return target;
                    }
                    else
                    {
                        // 判断目标类型是否是链表
                        if (typeof(IList).IsAssignableFrom(targetType))
                        {
                            // 根据目标类型创建目标对象链表
                            IList target = Activator.CreateInstance(targetType) as IList;
                            // 获取目标对象链表的元素类型
                            Type elementType = targetType.GetElementType();
                            // 遍历并转换原始集合对象数据到目标对象链表中
                            foreach (var item in collection)
                            {
                                // 将当前原始数据项转换为目标元素类型并添加到对应的目标对象链表中
                                target.Add(this.ConvertType(item, elementType));
                            }
                            // 返回目标对象链表
                            return target;
                        }
                    }
                }
            }
            // 转换并返回目标对象
            return Convert.ChangeType(source, targetType);
        }
    }
}

关于C#中使用ArcGIS开发接口“ISaveAs2.SaveAs”无法写入数据的说明

在ArcGIS的二次开发中我们可以通过接口“ISaveAs2”的“SaveAs”方法将数据保存到本地。但是由于该方法将返回一个IDataset对象来绑定输出,因此在.NET开发时我们必须使用“Marshal.ReleaseComObject”方法来将该IDataset对象释放,否则数据将无法完整写入本地文件中。以下为官方说明:
Note, SaveAs will return a RasterDataset, to prevent from ISaveAs holding the output, .NET ReleaseCOMObject needs to be called to release the referene to the output raster dataset: System.Runtime.InteropServices.Marshal.ReleaseComObject(outRasterDS);

// 保存数据
IDataset dataset = saveAs2.SaveAs(fileName, workspace, "TIFF");
// 释放IDataset对象
Marshal.ReleaseComObject(dataset);