diff --git a/DH.Commons/DH.Commons.csproj b/DH.Commons/DH.Commons.csproj index 62425ed..1cbfe74 100644 --- a/DH.Commons/DH.Commons.csproj +++ b/DH.Commons/DH.Commons.csproj @@ -11,14 +11,7 @@ <Platforms>AnyCPU;x64</Platforms> </PropertyGroup> - - - - - - - - + <ItemGroup> <PackageReference Include="AntdUI" Version="1.8.9" /> diff --git a/DH.Commons/Helper/AttributeHelper.cs b/DH.Commons/Helper/AttributeHelper.cs new file mode 100644 index 0000000..5236ed2 --- /dev/null +++ b/DH.Commons/Helper/AttributeHelper.cs @@ -0,0 +1,162 @@ +using DH.Commons.Enums; +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using static DH.Commons.Enums.EnumHelper; + + +namespace DH.Commons.Enums +{ + /// <summary> + /// 设备特性,指示该信息的设备类型,适用于设备信息和配置信息 + /// </summary> + public class DeviceAttribute : Attribute + { + /// <summary> + /// 设备类型 + /// </summary> + public string TypeCode { get; set; } + + public string TypeDescription { get; set; } + + /// <summary> + /// 特性修饰类别 + /// </summary> + public DeviceAttributeType AttrType { get; set; } + + public DeviceAttribute(string typeCode, string typeDesc, EnumHelper.DeviceAttributeType attrType) + { + TypeCode = typeCode; + TypeDescription = typeDesc; + AttrType = attrType; + } + } + + /// <summary> + /// 预置状态特性 指定该修饰信息的前置状态允许范围 + /// </summary> + public class PreStateAttribute : Attribute + { + public int PreState { get; set; } + public PreStateAttribute(int _preState) + { + PreState = _preState; + } + + /// <summary> + /// 检查当前待执行操作的前置状态要求是否合法 + /// </summary> + /// <param name="currentState"></param> + /// <returns></returns> + public bool CheckPreStateValid(int currentState) + { + return (currentState & PreState) == currentState; + } + } + + public class ColorSelectAttribute : Attribute + { + public string SelectedColor { get; set; } + public ColorSelectAttribute(string selectedColor) + { + SelectedColor = selectedColor; + } + } + + public class FontColorSelectAttribute : Attribute + { + public string SelectedColor { get; set; } + public FontColorSelectAttribute(string selectedColor) + { + SelectedColor = selectedColor; + } + } + + public enum InvokeType + { + /// <summary> + /// 不公开调用 + /// </summary> + [Description("不公开调用")] + NoneInvoke = 0, + /// <summary> + /// 测试调用 + /// </summary> + [Description("测试调用")] + TestInvoke = 1, + /// <summary> + /// 标定调用 + /// </summary> + [Description("标定调用")] + CalibInvoke = 2, + } + + /// <summary> + /// 用来修饰对外开放的调用方法的特性 + /// 调用方法参数顺序:IOperationConfig,InvokeDevice,SourceDevice + /// </summary> + public class ProcessMethodAttribute : Attribute + { + public string MethodCode { get; set; } + public string MethodDesc { get; set; } + + /// <summary> + /// 是否提供人工调用测试 + /// </summary> + public InvokeType InvokeType { get; set; } + + public string DeviceType { get; set; } + + public ProcessMethodAttribute(string deviceType, string code, string description, InvokeType invokeType) + { + DeviceType = deviceType; + MethodCode = code; + MethodDesc = description; + InvokeType = invokeType; + } + } + + public class SwitchDisplayAttribute : Attribute + { + public string SwitchName { get; set; } + + public bool SwithOnStatus { get; set; } = true; + + public SwitchDisplayAttribute(string name, bool status) + { + SwitchName = name; + SwithOnStatus = status; + } + } + + public class ElementAttribute : Attribute + { + public string Name { get; set; } + + public string Desc { get; set; } + + public string IconPath { get; set; } + + public bool IsShowInToolBar { get; set; } + + public ElementAttribute(string desc, string iconPath, bool isShowInToolBar = true, [CallerMemberName] string name = "") + { + Name = name; + Desc = desc; + IconPath = iconPath; + IsShowInToolBar = isShowInToolBar; + } + } + + public class ProcessAttribute : Attribute + { + public string ProcessCode { get; set; } + public DeviceAttributeType AttrType { get; set; } + + public ProcessAttribute(string stationCode, DeviceAttributeType attrType) + { + ProcessCode = stationCode; + AttrType = attrType; + } + } +} \ No newline at end of file diff --git a/DH.Commons/Helper/EnumHelper.cs b/DH.Commons/Helper/EnumHelper.cs index 019614c..3b0d2a6 100644 --- a/DH.Commons/Helper/EnumHelper.cs +++ b/DH.Commons/Helper/EnumHelper.cs @@ -251,7 +251,38 @@ namespace DH.Commons.Enums [Description("测量结果")] MeasureResult = 31, } - + + public enum LogLevel + { + [Description("详细")] + [ColorSelect("White")] + [FontColorSelect("Green")] + Detail = 2, + [Description("信息")] + [ColorSelect("White")] + [FontColorSelect("Dark")] + Information = 3, + [Description("辅助")] + [ColorSelect("White")] + [FontColorSelect("Blue")] + Assist = 4, + [Description("动作")] + [ColorSelect("DarkGreen")] + [FontColorSelect("Yellow")] + Action = 5, + [Description("错误")] + [ColorSelect("Orange")] + [FontColorSelect("White")] + Error = 6, + [Description("警报")] + [ColorSelect("Brown")] + [FontColorSelect("White")] + Warning = 7, + [Description("异常")] + [ColorSelect("Red")] + [FontColorSelect("White")] + Exception = 8, + } //public enum CameraDriverType //{ // Halcon, diff --git a/DH.Commons/Helper/LoggerHelper.cs b/DH.Commons/Helper/LoggerHelper.cs new file mode 100644 index 0000000..eba4c68 --- /dev/null +++ b/DH.Commons/Helper/LoggerHelper.cs @@ -0,0 +1,126 @@ +using DH.Commons.Helper; +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using static DH.Commons.Enums.EnumHelper; + +namespace DH.Commons.Enums +{ + public class LoggerHelper + { + public event Action<DateTime, string> OnLogExceptionRaised; + + public string LogPath { get; set; } + public string LogPrefix { get; set; } + + LogLevel LogLevel = LogLevel.Information; + + public LoggerHelper() { } + public LoggerHelper(string logPath, string logPrefix, LogLevel logLevel = LogLevel.Information) + { + LogPath = logPath; + LogPrefix = logPrefix; + + LogLevel = logLevel; + } + + public void SetLogLevel(LogLevel logLevel) + { + if (LogLevel != logLevel) + LogLevel = logLevel; + } + ////耗时操作从 _taskFactory分配线程 + //public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning); + readonly ConcurrentQueue<LogMsg> _logQueue = new ConcurrentQueue<LogMsg>(); + Task _logTask = null; + readonly object _logLock = new object(); + + public async void LogAsync(LogMsg msg) + { + await Task.Run(() => + { + _logQueue.Enqueue(msg); + + lock (_logLock) + { + if (_logTask == null) + { + _logTask = Task.Run(async () => + { + string filePath = Path.Combine(LogPath, $"{(string.IsNullOrWhiteSpace(LogPrefix) ? "Log_" : ("Log_" + LogPrefix + "_"))}{DateTime.Now.ToString("yyyyMMdd")}.txt"); + try + { + if (!StaticHelper.CheckFilesCanUse(filePath)) + { + OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}被占用,无法写入"); + return; + } + using (StreamWriter writer = new StreamWriter(filePath, true, System.Text.Encoding.UTF8)) + { + while (true) + { + if (!Directory.Exists(LogPath)) + { + Directory.CreateDirectory(LogPath); + } + + while (_logQueue.Count > 0) + { + if (_logQueue.TryDequeue(out LogMsg log)) + { + if (log.LogLevel >= LogLevel) + { + writer.WriteLine($"{log.LogTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}[{log.ThreadId}]\t{log.LogLevel.GetEnumDescription()}\t{log.Msg}"); + } + } + } + writer.Flush(); + + await Task.Delay(2000); + } + } + } + catch (Exception ex) + { + //OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常:/*{ex.GetExceptionMessage()*/}"); + OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常"); + } + }); + } + } + }); + } + + public void LogAsync(DateTime dt, LogLevel logLevel, string msg) + { + LogAsync(new LogMsg(dt, logLevel, msg)); + } + } + + public class LogMsg + { + public DateTime LogTime { get; set; } + public LogLevel LogLevel { get; set; } + //public string Prefix { get; set; } + public string Msg { get; set; } + + public string MsgSource { get; set; } + + public int ThreadId { get; set; } + + public LogMsg() { } + public LogMsg(DateTime dt, LogLevel logLevel, string msg) + { + LogTime = dt; + LogLevel = logLevel; + Msg = msg; + } + + public override string ToString() + { + return $"{LogTime.ToString("HH:mm:ss.fff")}\t{MsgSource}\t{Msg}"; + } + } +} diff --git a/DH.Commons/Helper/StaticHelper.cs b/DH.Commons/Helper/StaticHelper.cs new file mode 100644 index 0000000..e80421b --- /dev/null +++ b/DH.Commons/Helper/StaticHelper.cs @@ -0,0 +1,677 @@ +using Microsoft.CSharp.RuntimeBinder; + +using System.Collections.ObjectModel; +using System.Drawing.Imaging; +using System.Dynamic; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +using System.Runtime.Serialization.Formatters.Binary; + +namespace DH.Commons.Helper +{ + public static class StaticHelper + { + /// <summary> + /// 数值转换为byte数组 高位在前,低位在后 + /// </summary> + /// <param name="number"></param> + /// <param name="size"></param> + /// <returns></returns> + public static byte[] IntToBytes(this int number, int size = 2) + { + byte[] result = new byte[size]; + + int temp = size; + while (temp > 0) + { + result[size - temp] = (byte)(number >> ((temp - 1) * 8) & 0xff); + + temp--; + } + + return result; + } + + /// <summary> + /// 字节数组转换为整数 + /// </summary> + /// <param name="data">字节数组</param> + /// <param name="HtL">true:数组序号低的在高位 false:数组序号低的在低位</param> + /// <returns></returns> + public static int BytesToInt(this byte[] data, bool HtL = true) + { + int res = 0; + + for (int i = 0; i < data.Length; i++) + { + int index = i; + + if (HtL) + { + index = data.Length - 1 - i; + } + + res += data[index] << (8 * i); + } + + return res; + } + + /// <summary> + /// 获取一个类指定的属性值 + /// </summary> + /// <param name="info">object对象</param> + /// <param name="field">属性名称</param> + /// <returns></returns> + public static object GetPropertyValue(object info, string field) + { + if (info == null) return null; + Type t = info.GetType(); + IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi; + return property.First().GetValue(info, null); + } + + /// <summary> + /// 将32位整形拆分为无符号16位整形 + /// </summary> + /// <param name="num">需要拆分的32位整形</param> + /// <param name="bitNum">拆分为16位整形的位数 1或者2</param> + /// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param> + /// <returns></returns> + public static List<ushort> ParseIntToUnsignShortList(this int num, int bitNum = 2, bool HtL = false) + { + if (bitNum == 2) + { + ushort high = (ushort)(num >> 16); + ushort low = (ushort)num; + + if (HtL) + { + return new List<ushort>() { high, low }; + } + else + { + return new List<ushort>() { low, high }; + } + } + else + { + if (num < 0) + { + num = ushort.MaxValue + 1 + num; + } + + return new List<ushort>() { (ushort)num }; + } + } + + /// <summary> + /// 将32位整形数组拆分为无符号16位整形数组 + /// </summary> + /// <param name="list">需要拆分的32位整形</param> + /// <param name="bitNum">拆分为16位整形的位数 1或者2</param> + /// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param> + /// <returns></returns> + public static List<ushort> ParseIntToUnsignShortList(this List<int> list, int bitNum = 2, bool HtL = false) + { + return list.SelectMany(u => u.ParseIntToUnsignShortList(bitNum, HtL)).ToList(); + } + + /// <summary> + /// 将ushort的集合转换为16位带符号整形 + /// </summary> + /// <param name="numList"></param> + /// <param name="bitNum">合并的位数 1或者2</param> + /// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param> + /// <returns></returns> + public static List<int> ParseUnsignShortListToInt(this List<int> numList, int bitNum = 2, bool HtL = false) + { + if (bitNum == 1) + { + return numList.ConvertAll(n => + { + int num = n; + if (num > short.MaxValue) + { + num = num - ushort.MaxValue - 1; + } + + return num; + }); + } + else + { + List<int> list = new List<int>(); + for (int i = 0; i < numList.Count; i += 2) + { + int high = HtL ? numList[i] : numList[i + 1]; + int low = HtL ? numList[i + 1] : numList[i]; + list.Add((high << 16) | low); + } + + return list; + } + } + + //public static T DeepSerializeClone<T>(this T t) + //{ + // return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(t)); + //} + + public static void DataFrom<T1, T2>(this T1 destT, T2 sourceT, List<string> exceptionProps = null) where T1 : class where T2 : class + { + if (sourceT == null) + { + destT = null; + return; + } + + PropertyInfo[] propDest = destT.GetType().GetProperties();//.Where(p => !(p.GetMethod.IsVirtual && !p.GetMethod.IsFinal)).ToArray(); + PropertyInfo[] propSource = sourceT.GetType().GetProperties(); + + Array.ForEach(propDest, prop => + { + if (exceptionProps == null || !exceptionProps.Contains(prop.Name)) + { + if (prop.CanWrite) + { + PropertyInfo propS = propSource.FirstOrDefault(p => p.Name == prop.Name); + if (propS != null && propS.CanRead) + { + prop.SetValue(destT, propS.GetValue(sourceT)); + } + } + } + }); + } + + + //RtlMoveMemory + [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)] + public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); + [HandleProcessCorruptedStateExceptions] + //public static Bitmap CopyBitmap(this Bitmap source) + //{ + // Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat); + // try + // { + // int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8; + // if (PixelSize == 1) + // { + // ColorPalette cp = clone.Palette; + // for (int i = 0; i < 256; i++) + // { + // cp.Entries[i] = Color.FromArgb(255, i, i, i); + // } + // clone.Palette = cp; + // } + + // Rectangle rect = new Rectangle(0, 0, source.Width, source.Height); + // BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat); + // BitmapData cloneData = clone.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat); + // if (source.Width % 4 == 0) + // { + // unsafe + // { + // CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(sourceData.Stride * sourceData.Height)); + // } + // } + // else + // { + // Parallel.For(0, source.Height, h => + // { + // unsafe + // { + // CopyMemory(cloneData.Scan0 + h * sourceData.Stride, sourceData.Scan0 + h * sourceData.Stride, (uint)sourceData.Width); + // } + // }); + // } + + // clone.UnlockBits(cloneData); + // source.UnlockBits(sourceData); + + // } + // catch (Exception ex) + // { + // return clone; + // } + + // return clone; + //} + public static Bitmap CopyBitmap(this Bitmap source) + { + Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat); + + try + { + int pixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8; + if (pixelSize == 1) + { + ColorPalette cp = clone.Palette; + for (int i = 0; i < 256; i++) + { + cp.Entries[i] = Color.FromArgb(255, i, i, i); + } + clone.Palette = cp; + } + + Rectangle rect = new Rectangle(0, 0, source.Width, source.Height); + BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat); + BitmapData cloneData = clone.LockBits(rect, ImageLockMode.WriteOnly, source.PixelFormat); + + int stride = sourceData.Stride; + int height = sourceData.Height; + + if (stride % 4 == 0) + { + unsafe + { + CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(stride * height)); + } + } + else + { + Parallel.For(0, height, h => + { + unsafe + { + CopyMemory(cloneData.Scan0 + h * stride, sourceData.Scan0 + h * stride, (uint)stride); + } + }); + } + source.UnlockBits(sourceData); clone.UnlockBits(cloneData); + } + catch (Exception ex) + { // Handle or log exception if needed + } return clone; } + + + public static Bitmap BitmapDeepClone(Bitmap source) + { + Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat); + + try + { + int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8; + if (PixelSize == 1) + { + ColorPalette cp = clone.Palette; + for (int i = 0; i < 256; i++) + { + cp.Entries[i] = Color.FromArgb(255, i, i, i); + } + clone.Palette = cp; + } + Rectangle rect = new Rectangle(0, 0, source.Width, source.Height); + BitmapData source_bitmap = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat); + BitmapData destination_bitmap = clone.LockBits(rect, ImageLockMode.ReadWrite, clone.PixelFormat); + + int depth_width = source_bitmap.Width * PixelSize; + + unsafe + { + byte* source_ptr = (byte*)source_bitmap.Scan0; + byte* destination_ptr = (byte*)destination_bitmap.Scan0; + + int offset = source_bitmap.Stride - depth_width; + + for (int i = 0; i < source_bitmap.Height; i++) + { + for (int j = 0; j < depth_width; j++, source_ptr++, destination_ptr++) + { + *destination_ptr = *source_ptr; + } + + source_ptr += offset; + destination_ptr += offset; + } + } + + source.UnlockBits(source_bitmap); + clone.UnlockBits(destination_bitmap); + } + catch (Exception ex) + { + + } + return clone; + } + + + + public static Bitmap HConnectBitmap(this Bitmap map1, Bitmap map2) + { + Bitmap connectImage = null; + if (map1 == null || map2 == null) + return null; + //横向拼接 + int width = map1.Width + map2.Width; + //高度不变 + int height = Math.Max(map1.Height, map2.Height); + connectImage = new Bitmap(width, height); + using (Graphics graph = Graphics.FromImage(connectImage)) + { + graph.DrawImage(connectImage, width, height); + graph.Clear(System.Drawing.Color.White); + graph.DrawImage(map1, 0, 0); + graph.DrawImage(map2, map1.Width, 0); + } + return connectImage; + } + + public static IntPtr FloatToIntptr(float[] bytes) + { + GCHandle hObject = GCHandle.Alloc(bytes, GCHandleType.Pinned); + return hObject.AddrOfPinnedObject(); + } + + // 将Btimap类转换为byte[]类函数 + public static byte[] GetBGRValues(Bitmap bmp, out int stride) + { + var rect = new Rectangle(0, 0, bmp.Width, bmp.Height); + var bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat); + stride = bmpData.Stride; + var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8; + var imgBytes = bmp.Height * rowBytes; + byte[] rgbValues = new byte[imgBytes]; + IntPtr ptr = bmpData.Scan0; + for (var i = 0; i < bmp.Height; i++) + { + Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes); + ptr += bmpData.Stride; + } + bmp.UnlockBits(bmpData); + return rgbValues; + } + /// <summary> + /// 缺陷灰度图转彩色图像函数 + /// </summary> + /// <param name="src">灰度图</param> + /// <returns>返回构造的伪彩色图像</returns> + public static Bitmap GrayMapToColorMap(this Bitmap src, Dictionary<int, Color> indexColorDict = null) + { + try + { + //Stopwatch sw = new Stopwatch(); + //sw.Start(); + + Bitmap dest = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb); + + int destHeight = dest.Height; + int destWidth = dest.Width; + + Rectangle rect = new Rectangle(0, 0, destWidth, destHeight); + BitmapData bmpDataDest = dest.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + BitmapData bmpDataSrc = src.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed); + int strideDest = bmpDataDest.Stride; + + int strideSrc = bmpDataSrc.Stride; + unsafe + { + byte* pDest = (byte*)bmpDataDest.Scan0.ToPointer(); + byte* pSrc = (byte*)bmpDataSrc.Scan0.ToPointer(); + + Parallel.For(0, destHeight, y => + { + Parallel.For(0, destWidth, x => + { + int pixel = pSrc[y * strideSrc + x]; + int startIndex = y * strideDest + x * 4; + if (pixel >= 0 && pixel <= 63) + { + Color color = Color.Red; + if (indexColorDict != null && indexColorDict.ContainsKey(pixel)) + { + color = indexColorDict[pixel]; + } + + byte R = color.R; + byte G = color.G; + byte B = color.B; + + pDest[startIndex] = B; + pDest[startIndex + 1] = G; + pDest[startIndex + 2] = R; + pDest[startIndex + 3] = 100; + } + else + { + pDest[startIndex] = 255; + pDest[startIndex + 1] = 255; + pDest[startIndex + 2] = 255; + pDest[startIndex + 3] = 0; + } + }); + }); + } + dest.UnlockBits(bmpDataDest); + src.UnlockBits(bmpDataSrc); + + //sw.Stop(); + //Console.WriteLine($"转换耗时:{sw.ElapsedMilliseconds}"); + + return dest; + } + catch (Exception ex) + { + return null; + } + } + + public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable<T> + { + List<T> sortedList = collection.OrderByDescending(x => x).ToList();//这里用降序 + for (int i = 0; i < sortedList.Count(); i++) + { + collection.Move(collection.IndexOf(sortedList[i]), i); + } + } + + /// <summary> + /// 获得字符串中开始和结束字符串中间的值 + /// </summary> + /// <param name="sourse"></param> + /// <param name="startstr"></param> + /// <param name="endstr"></param> + /// <returns></returns> + public static string GetMidString(string sourse, string startstr, string endstr) + { + string result = string.Empty; + int startindex, endindex; + try + { + startindex = sourse.IndexOf(startstr); + if (startindex == -1) + return result; + string tmpstr = sourse.Substring(startindex + startstr.Length); + endindex = tmpstr.IndexOf(endstr); + if (endindex == -1) + return result; + result = tmpstr.Remove(endindex); + } + catch (Exception ex) + { + return ""; + } + return result; + } + + /// <summary> + /// 获得字符串中开始和结束字符串中间的值 + /// </summary> + /// <param name="t">字符串</param> + /// <param name="k">开始</param> + /// <param name="j">结束</param> + /// <returns></returns> + private static string GetMidString2(string sourse, string startstr, string endstr) //截取指定文本,和易语言的取文本中间差不多 + { + try //异常捕捉 + { + var kn = sourse.IndexOf(startstr, StringComparison.Ordinal) + startstr.Length; + var jn = sourse.IndexOf(endstr, kn, StringComparison.Ordinal); + return sourse.Substring(kn, jn - kn); + } + catch //如果发现未知的错误,比如上面的代码出错了,就执行下面这句代码 + { + return ""; //返回空 + } + + } + + // 布尔类型转换为整型 + public static int ToInt(this object obj) + { + if (Convert.ToBoolean(obj) == true) + return 1; + else + return 0; + } + + // 整型转换为布尔类型 + public static bool ToBool(this object obj) + { + if (Convert.ToInt32(obj) == 1) + return true; + else + return false; + } + + public static object GetProperty(this object o, string member) + { + if (o == null) throw new ArgumentNullException("o"); + if (member == null) throw new ArgumentNullException("member"); + Type scope = o.GetType(); + IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider; + if (provider != null) + { + ParameterExpression param = Expression.Parameter(typeof(object)); + DynamicMetaObject mobj = provider.GetMetaObject(param); + GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(0, null) }); + DynamicMetaObject ret = mobj.BindGetMember(binder); + BlockExpression final = Expression.Block( + Expression.Label(CallSiteBinder.UpdateLabel), + ret.Expression + ); + LambdaExpression lambda = Expression.Lambda(final, param); + Delegate del = lambda.Compile(); + return del.DynamicInvoke(o); + } + else + { + return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null); + } + } + + #region 检测文件状态及操作方式选择 + [DllImport("kernel32.dll")] + private static extern IntPtr _lopen(string lpPathName, int iReadWrite); + [DllImport("kernel32.dll")] + private static extern bool CloseHandle(IntPtr hObject); + private const int OF_READWRITE = 2; + private const int OF_SHARE_DENY_NONE = 0x40; + private static readonly IntPtr HFILE_ERROR = new IntPtr(-1); + /// <summary> + /// 检测文件是否只读或被使用 + /// </summary> + /// <param name="FileNames">要检测的文件</param> + /// <returns>true可用,false在用或只读</returns> + public static bool CheckFilesCanUse(string fileName) + { + if (!File.Exists(fileName)) + return true;//文件不存在 + if ((File.GetAttributes(fileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) + return false; //文件只读 + IntPtr vHandle = _lopen(fileName, OF_READWRITE | OF_SHARE_DENY_NONE); + if (vHandle == HFILE_ERROR) + { + CloseHandle(vHandle); + return false; //文件被占用 + } + + CloseHandle(vHandle); //文件没被占用 + return true; + } + #endregion + + /// <summary> + /// 获取指定文件夹下所有的文件名称 + /// </summary> + /// <param name="folderName">指定文件夹名称,绝对路径</param> + /// <param name="fileFilter">文件类型过滤,根据文件后缀名,如:*,*.txt,*.xls</param> + /// <param name="isContainSubFolder">是否包含子文件夹</param> + /// <returns>ArrayList数组,为所有需要的文件路径名称</returns> + public static List<FileInfo> GetAllFilesByFolder(string folderName, string fileFilter, bool isContainSubFolder = false) + { + List<FileInfo> resList = new List<FileInfo>(); + try + { + DirectoryInfo currDir = new DirectoryInfo(folderName);//当前目录 + FileInfo[] currFiles = currDir.GetFiles(fileFilter);//当前目录文件 + foreach (FileInfo file in currFiles) + { + if (fileFilter.ToLower().IndexOf(file.Extension.ToLower()) >= 0) + { + resList.Add(file); + } + } + if (isContainSubFolder) + { + string[] subFolders = Directory.GetDirectories(folderName); + foreach (string subFolder in subFolders) + { + resList.AddRange(GetAllFilesByFolder(subFolder, fileFilter));//递归 + } + } + } + catch (Exception ex) + { + throw ex; + } + return resList; + } + + /// <summary> + /// 获取指定文件夹下所有的文件名称,不过滤文件类型 + /// </summary> + /// <param name="folderName">指定文件夹名称,绝对路径</param> + /// <param name="isContainSubFolder">是否包含子文件夹</param> + /// <returns>ArrayList数组,为所有需要的文件路径名称</returns> + public static List<FileInfo> GetAllFilesByFolder(string folderName, bool isContainSubFolder) + { + return GetAllFilesByFolder(folderName, "*", isContainSubFolder); + } + } + + public class Compare<T, C> : IEqualityComparer<T> + { + private Func<T, C> _getField; + public Compare(Func<T, C> getfield) + { + _getField = getfield; + } + public bool Equals(T x, T y) + { + return EqualityComparer<C>.Default.Equals(_getField(x), _getField(y)); + } + public int GetHashCode(T obj) + { + return EqualityComparer<C>.Default.GetHashCode(_getField(obj)); + } + } + + public static class ObjectExtensions + { + public static IEnumerable<T> DistinctBy<T, C>(this IEnumerable<T> source, Func<T, C> getfield) + { + return source.Distinct(new Compare<T, C>(getfield)); + } + + public static IQueryable<T> DistinctBy<T, C>(this IQueryable<T> source, Func<T, C> getfield) + { + return source.Distinct(new Compare<T, C>(getfield)); + } + } +}