439 lines
17 KiB
C#
439 lines
17 KiB
C#
using Common.Models;
|
||
using Microsoft.Win32;
|
||
using Newtonsoft;
|
||
using Newtonsoft.Json;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Runtime.Serialization;
|
||
using System.Runtime.Serialization.Formatters.Binary;
|
||
using System.Windows;
|
||
using System.Windows.Media;
|
||
using System.Xml.Serialization;
|
||
|
||
namespace Common
|
||
{
|
||
public class File_Operator
|
||
{
|
||
private static readonly object _lock = new object();
|
||
|
||
public static T Xml_Serialize<T>(string strFile, bool bSave, T param, out bool bReadOK) where T : class
|
||
{
|
||
lock (_lock)
|
||
{
|
||
bReadOK = true;
|
||
XmlSerializer xs = null;
|
||
|
||
// 针对 BaseBottleBox 集合,显式指定所有派生类
|
||
if (typeof(T) == typeof(ProjectProperty))
|
||
{
|
||
Type[] extraTypes = new Type[]
|
||
{
|
||
typeof(BaseBottleBox),
|
||
typeof(SampleBottleBoxModel),
|
||
typeof(SourceLiquidBottleBoxModel),
|
||
typeof(SourcePowderBottleBoxModel),
|
||
typeof(SourcePowderBottleBoxModel_125ml),
|
||
typeof(TipBoxModel),
|
||
typeof(SourcePowderBottleModel),
|
||
typeof(TipHeadItem)
|
||
};
|
||
xs = new XmlSerializer(typeof(ProjectProperty), extraTypes);
|
||
}
|
||
else
|
||
{
|
||
xs = new XmlSerializer(param.GetType());
|
||
}
|
||
|
||
try
|
||
{
|
||
// 使用 using 自动释放流(避免资源泄漏)
|
||
if (bSave)
|
||
{
|
||
using (Stream stream = new FileStream(strFile, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||
{
|
||
xs.Serialize(stream, param);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (File.Exists(strFile))
|
||
{
|
||
using (Stream stream = new FileStream(strFile, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||
{
|
||
param = xs.Deserialize(stream) as T;
|
||
}
|
||
return param;
|
||
}
|
||
else
|
||
{
|
||
// 文件不存在时,先创建并序列化默认值
|
||
using (Stream stream = new FileStream(strFile, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||
{
|
||
xs.Serialize(stream, param);
|
||
}
|
||
// 重新读取
|
||
using (Stream stream = new FileStream(strFile, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||
{
|
||
param = xs.Deserialize(stream) as T;
|
||
}
|
||
return param;
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
bReadOK = false;
|
||
MessageBox.Show($"序列化失败:{ex.Message}\n{ex.StackTrace}", "错误");
|
||
}
|
||
return null;
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// XML文件读写
|
||
/// 保存配置参数 bReadOK==false为发生异常
|
||
/// </summary>
|
||
/// <typeparam name="T">类类型</typeparam>
|
||
/// <param name="strFile">完整文件路径名</param>
|
||
/// <param name="bSave">true:保存;false:读取</param>
|
||
/// <param name="param">要进行序列化或反序列化的对象实例</param>
|
||
/// <param name="bReadOK">是否读写成功,有异常</param>
|
||
/// <returns>读取的数据</returns>
|
||
//public static T Xml_Serialize<T>(string strFile, bool bSave, T param, out bool bReadOK) where T : class
|
||
//{
|
||
// lock (_lock)
|
||
// {
|
||
// bReadOK = true;
|
||
// XmlSerializer xs = new XmlSerializer(param.GetType());
|
||
// try
|
||
// {
|
||
// if (bSave)
|
||
// {
|
||
// //创建一个 FileStream 对象,以 FileMode.Create 模式打开文件,用于写入数据。
|
||
// //使用 xs.Serialize 方法将 param 对象序列化为 XML 数据,并写入文件。
|
||
// //关闭文件流。
|
||
// Stream stream = new FileStream(strFile, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||
// xs.Serialize(stream, param);
|
||
// stream.Close();
|
||
// }
|
||
// else
|
||
// {
|
||
// //检查文件是否存在。
|
||
// //如果文件存在,创建一个 FileStream 对象,以 FileMode.Open 模式打开文件,用于读取数据。
|
||
// //使用 xs.Deserialize 方法将文件中的 XML 数据反序列化为 T 类型的对象,并赋值给 param。
|
||
// //关闭文件流,并返回反序列化后的对象。
|
||
|
||
// if (File.Exists(strFile))
|
||
// {
|
||
// Stream stream = new FileStream(strFile, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||
// param = xs.Deserialize(stream) as T;
|
||
// stream.Close();
|
||
// return param;
|
||
// }
|
||
// else
|
||
// {
|
||
// //如果文件不存在,先创建一个 FileStream 对象,以 FileMode.Create 模式打开文件,将 param 对象序列化为 XML 数据并写入文件。
|
||
// //再次打开文件,读取其中的 XML 数据进行反序列化,并返回反序列化后的对象。
|
||
// Stream stream = new FileStream(strFile, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||
// xs.Serialize(stream, param);
|
||
// stream.Close();
|
||
|
||
// stream = new FileStream(strFile, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||
// param = xs.Deserialize(stream) as T;
|
||
// stream.Close();
|
||
// return param;
|
||
// }
|
||
// }
|
||
// }
|
||
// catch (Exception ex)
|
||
// {
|
||
// bReadOK = false;
|
||
// MessageBox.Show(ex.Message);
|
||
// }
|
||
// return null;
|
||
// }
|
||
//}
|
||
|
||
/// <summary>
|
||
/// 通过文件名寻找同目录下的其他同类型文件
|
||
/// </summary>
|
||
/// <param name="file">文件的绝对路径名</param>
|
||
public static List<string> GetFile(string file)
|
||
{
|
||
List<string> listFile = new List<string>();
|
||
if (!string.IsNullOrEmpty(file) && File.Exists(file))
|
||
{
|
||
int index = file.LastIndexOf("\\");
|
||
if (-1 == index) return null;
|
||
string path = file.Substring(0, index);//文件所在文件夹路径
|
||
string name = file.Substring(index);//文件名
|
||
string postfix = "";//取出后缀名
|
||
if (name.Contains("."))
|
||
{
|
||
postfix = name.Substring(name.LastIndexOf('.'));//例: .txt
|
||
}
|
||
else
|
||
{
|
||
return null;
|
||
}
|
||
string[] files = null;
|
||
try
|
||
{
|
||
files = Directory.GetFiles(path);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show(ex.Message);
|
||
return null;
|
||
}
|
||
foreach (var item in files)
|
||
{
|
||
int nIndex = item.IndexOf(postfix);
|
||
if (nIndex != -1)
|
||
{
|
||
listFile.Add(item);
|
||
}
|
||
}
|
||
}
|
||
return listFile;
|
||
}
|
||
|
||
|
||
#region 对注册表进行读写
|
||
//public static void CreatRegistryPath(string strPathName)
|
||
//{
|
||
// try
|
||
// {
|
||
// RegistryKey key = Registry.LocalMachine;
|
||
// //RegistryKey software = key.CreateSubKey("software\\test");
|
||
// RegistryKey software = key.CreateSubKey("software\\" + strPathName);
|
||
// key.Close();
|
||
// }
|
||
// catch (Exception ex)
|
||
// {
|
||
// MessageBox.Show("对注册表创建路径时出现异常!" + ex.Message);
|
||
// }
|
||
//}
|
||
|
||
//public static void DeleteRegistryPath(string strPathName)
|
||
//{
|
||
// try
|
||
// {
|
||
// RegistryKey key = Registry.LocalMachine;
|
||
// //key.DeleteSubKey("software\\test", true);
|
||
// key.DeleteSubKey("software\\" + strPathName, true);
|
||
// key.Close();
|
||
// }
|
||
// catch (Exception ex)
|
||
// {
|
||
// MessageBox.Show("对注册表删除路径时出现异常!" + ex.Message);
|
||
// }
|
||
//}
|
||
|
||
//public static void SetRegistryValue(string strPathName, string strKey, string strValue)
|
||
//{
|
||
// try
|
||
// {
|
||
// RegistryKey key = Registry.LocalMachine;
|
||
// RegistryKey software = key.OpenSubKey("software\\" + strPathName, true);
|
||
// //software.SetValue("test", "博客园");
|
||
// software.SetValue(strKey, strValue);
|
||
// key.Close();
|
||
// }
|
||
// catch (Exception ex)
|
||
// {
|
||
// MessageBox.Show("对注册表设置键值时出现异常!" + ex.Message);
|
||
// }
|
||
//}
|
||
|
||
//public static string GetRegistryValue(string strPathName, string strKey)
|
||
//{
|
||
// try
|
||
// {
|
||
// RegistryKey Key = Registry.LocalMachine;
|
||
// RegistryKey myreg = Key.OpenSubKey("software\\" + strPathName, true);
|
||
// //info = myreg.GetValue("test").ToString();
|
||
// string strValue = myreg.GetValue(strKey).ToString();
|
||
// myreg.Close();
|
||
// return strValue;
|
||
// }
|
||
// catch (Exception ex)
|
||
// {
|
||
// MessageBox.Show("对注册表获取值时出现异常!" + ex.Message);
|
||
// return "";
|
||
// }
|
||
//}
|
||
|
||
//public static void DeleteRegistryKey(string strPathName, string strKey)
|
||
//{
|
||
// try
|
||
// {
|
||
// RegistryKey delKey = Registry.LocalMachine.OpenSubKey("Software\\" + strPathName, true);
|
||
// //delKey.DeleteValue("test");
|
||
// delKey.DeleteValue(strKey);
|
||
// delKey.Close();
|
||
// }
|
||
// catch (Exception ex)
|
||
// {
|
||
// MessageBox.Show("对注册表删除键值时出现异常!" + ex.Message);
|
||
// }
|
||
//}
|
||
#endregion
|
||
|
||
|
||
|
||
#region 深度拷贝
|
||
public static T DeepCopy<T>(T obj)
|
||
{
|
||
if (obj == null) return default;
|
||
//var json = JsonConvert.SerializeObject(obj);
|
||
//return JsonConvert.DeserializeObject<T>(json);
|
||
|
||
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
|
||
string json = JsonConvert.SerializeObject(obj, settings);
|
||
return JsonConvert.DeserializeObject<T>(json, settings);
|
||
}
|
||
|
||
[Obsolete("弃用,使用上面的DeepCopy方法")]
|
||
public static T DeepCopy_1<T>(T obj)
|
||
{
|
||
if (obj == null) return default;
|
||
|
||
Type actualType = obj.GetType();
|
||
|
||
// 处理值类型和字符串
|
||
// 处理值类型和字符串
|
||
if (actualType.IsValueType || actualType == typeof(string))
|
||
return obj;
|
||
|
||
// 处理数组
|
||
if (actualType.IsArray)
|
||
{
|
||
var elementType = typeof(T).GetElementType();
|
||
var sourceArray = (Array)(object)obj;
|
||
var copiedArray = Array.CreateInstance(elementType, sourceArray.Length);
|
||
for (int i = 0; i < sourceArray.Length; i++)
|
||
{
|
||
copiedArray.SetValue(DeepCopy((dynamic)sourceArray.GetValue(i)), i);
|
||
}
|
||
return (T)(object)copiedArray;
|
||
}
|
||
|
||
// 处理集合(如 List, ObservableCollection)
|
||
// 处理集合(优先直接创建目标类型,避免冗余转换)
|
||
if (typeof(IEnumerable).IsAssignableFrom(actualType) && actualType != typeof(string))
|
||
{
|
||
return DeepCopyCollection<T>(obj);
|
||
}
|
||
|
||
// 处理普通对象(核心修改)
|
||
// 关键修改2:按“实际类型”创建实例(而非 T 的声明类型)
|
||
object copy = Activator.CreateInstance(actualType);
|
||
// 关键修改3:拷贝所有字段(包括私有字段+派生类特有字段)
|
||
FieldInfo[] fields = actualType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||
|
||
foreach (var field in fields)
|
||
{
|
||
if (field.IsStatic) continue; // 跳过静态字段
|
||
|
||
var value = field.GetValue(obj);
|
||
// 递归深拷贝字段值(保持原逻辑)
|
||
var copiedValue = DeepCopy((dynamic)value);
|
||
field.SetValue(copy, copiedValue);
|
||
}
|
||
|
||
// 强制转换为 T(因为实际类型是 T 的派生类,转换安全)
|
||
return (T)copy;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 专门处理 ObservableCollection 类型属性(支持只读属性)
|
||
/// </summary>
|
||
private static void DeepCopyObservableCollectionProperty(PropertyInfo property, object sourceObj, object targetObj)
|
||
{
|
||
// 获取源集合和元素类型
|
||
var sourceCollection = property.GetValue(sourceObj) as IEnumerable;
|
||
var elementType = property.PropertyType.GetGenericArguments()[0];
|
||
|
||
// 创建新的 ObservableCollection 实例(匹配原属性类型)
|
||
var targetCollection = Activator.CreateInstance(property.PropertyType) as IList;
|
||
if (targetCollection == null)
|
||
throw new InvalidOperationException($"无法创建 {property.PropertyType.Name} 实例");
|
||
|
||
// 深拷贝集合元素并添加到新集合
|
||
foreach (var item in sourceCollection)
|
||
{
|
||
var copiedItem = DeepCopy((dynamic)item);
|
||
targetCollection.Add(copiedItem);
|
||
}
|
||
|
||
// 给目标对象赋值:可写属性直接 SetValue,只读属性通过底层字段赋值
|
||
if (property.CanWrite)
|
||
{
|
||
property.SetValue(targetObj, targetCollection);
|
||
}
|
||
else
|
||
{
|
||
// 匹配只读属性的底层字段(常见命名规范:_propertyName 或 m_propertyName)
|
||
var fieldName = $"_{char.ToLower(property.Name[0])}{property.Name.Substring(1)}";
|
||
var field = targetObj.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||
|
||
// 若未匹配到,尝试 mPropertyName 规范
|
||
if (field == null)
|
||
{
|
||
fieldName = $"m{property.Name}";
|
||
field = targetObj.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||
}
|
||
|
||
if (field != null && field.FieldType == property.PropertyType)
|
||
{
|
||
field.SetValue(targetObj, targetCollection);
|
||
}
|
||
else
|
||
{
|
||
throw new InvalidOperationException($"无法给只读属性 {property.DeclaringType.Name}.{property.Name} 赋值,请检查字段命名(预期:{fieldName})");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 优化集合深拷贝:直接创建目标类型集合,避免 List 中转
|
||
/// </summary>
|
||
private static T DeepCopyCollection<T>(T sourceCollection)
|
||
{
|
||
var sourceType = typeof(T);
|
||
var elementType = sourceType.IsGenericType ? sourceType.GetGenericArguments()[0] : typeof(object);
|
||
|
||
// 直接创建目标类型的集合实例(如 ObservableCollection<SampleBottleModel>)
|
||
var targetCollection = Activator.CreateInstance(sourceType) as IList;
|
||
if (targetCollection == null)
|
||
throw new InvalidOperationException($"无法创建集合类型 {sourceType.Name} 实例");
|
||
|
||
// 深拷贝每个元素并添加到新集合
|
||
foreach (var item in (IEnumerable)sourceCollection)
|
||
{
|
||
var copiedItem = DeepCopy((dynamic)item);
|
||
targetCollection.Add(copiedItem);
|
||
}
|
||
|
||
return (T)targetCollection;
|
||
}
|
||
|
||
public static ObservableCollection<T> DeepCopyObservableCollection<T>(ObservableCollection<T> source)
|
||
{
|
||
// 序列化为 JSON 字符串
|
||
var json = JsonConvert.SerializeObject(source);
|
||
// 从 JSON 字符串反序列化为新对象
|
||
return JsonConvert.DeserializeObject<ObservableCollection<T>>(json);
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|