using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
namespace JWH
{
public static class ExtensionReflection
{
public static bool IsDesignMode = LicenseManager.UsageMode == LicenseUsageMode.Designtime;
///
/// 속성 정보를 캐싱하기 위한 사전입니다.
///
private static readonly ConcurrentDictionary> PropertyCache =
new ConcurrentDictionary>();
///
/// 주어진 타입의 속성 정보를 캐싱하여 반환합니다.
///
/// 대상 타입
/// 속성 정보 사전
private static Dictionary GetCachedProperties(Type type)
{
return PropertyCache.GetOrAdd(type, t =>
t.GetProperties().ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase));
}
#region [ PropertiesCopy ] --------------------------------------------
///
/// 현재 객체의 속성 값을 대상 객체의 속성에 복사합니다.
///
/// 원본 객체
/// 대상 객체
/// 기존 값을 덮어쓸지 여부
public static void PropertiesCopy(this object sender, object dest, bool overwrite = true)
{
if (sender == null) throw new ArgumentNullException(nameof(sender));
if (dest == null) throw new ArgumentNullException(nameof(dest));
var sourceProperties = GetCachedProperties(sender.GetType());
var destProperties = GetCachedProperties(dest.GetType());
foreach (var sourceProp in sourceProperties)
{
if (!destProperties.TryGetValue(sourceProp.Key, out var destProp)) continue;
if (!destProp.CanWrite) continue;
if (typeof(IList).IsAssignableFrom(sourceProp.Value.PropertyType))
{
var sourceList = sourceProp.Value.GetValue(sender) as IList;
if (sourceList == null) continue;
var destList = destProp.GetValue(dest) as IList ?? (IList)Activator.CreateInstance(sourceProp.Value.PropertyType);
if (overwrite) destList.Clear();
foreach (var item in sourceList)
{
destList.Add(item);
}
destProp.SetValue(dest, destList);
}
else
{
var sourceValue = sourceProp.Value.GetValue(sender);
if (!overwrite && destProp.GetValue(dest) != null) continue;
destProp.SetValue(dest, sourceValue);
}
}
}
///
/// DataTable의 데이터를 대상 객체의 속성에 복사합니다.
///
/// 원본 DataTable
/// 대상 객체
public static void PropertiesCopy(this DataTable sender, object dest)
{
try
{
if (sender.Rows.Count < 1) return;
DataRow row = sender.Rows[0];
foreach (DataColumn column in sender.Columns)
{
try
{
PropertyInfo destProp = dest.GetType().GetProperty(column.ColumnName, column.DataType);
if (destProp == null) continue;
try
{
var obj = row[column.ColumnName];
destProp.SetValue(dest, obj);
}
catch
{
// Object of type 'System.DBNull' cannot be converted to type 'System.String'.
}
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
throw ex;
}
}
///
/// Dictionary의 데이터를 대상 객체의 속성에 복사합니다.
///
/// 원본 Dictionary
/// 대상 객체
public static void PropertiesCopy(this Dictionary sender, object dest)
{
try
{
foreach (KeyValuePair item in sender)
{
try
{
PropertyInfo destProp = dest.GetType().GetProperty(item.Key);
if (destProp == null) continue;
if (!destProp.CanWrite) continue;
var obj = Convert.ChangeType(item.Value, destProp.PropertyType);
destProp.SetValue(dest, obj);
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
}
}
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
throw ex;
}
}
#endregion
#region [ Property Set/Get ] ------------------------------------------
///
/// 주어진 값을 현재 객체의 속성에 설정합니다.
///
/// 대상 객체
/// 속성 이름
/// 설정할 값
public static void PropertySet(this object sender, string name, object value)
{
PropertyInfo property;
GetCachedProperties(sender.GetType()).TryGetValue(name, out property);
if (property == null || !property.CanWrite) return;
if (value != null && property.PropertyType != value.GetType())
{
value = Convert.ChangeType(value, property.PropertyType);
}
property.SetValue(sender, value);
}
///
/// 객체의 특정 속성 값을 반환합니다.
///
/// 대상 객체
/// 속성 이름
/// 속성 값
public static object PropertyGet(this object sender, string name)
{
PropertyInfo property;
GetCachedProperties(sender.GetType()).TryGetValue(name, out property);
return property?.GetValue(sender);
}
#endregion
#region [ ToClass() ] -------------------------------------------------
///
/// DataTable을 제네릭 객체 리스트로 변환합니다.
///
/// 제네릭 객체 타입
/// 원본 DataTable
/// 제네릭 객체 배열
public static T[] ToClass(this DataTable dataTable) where T : class, new()
{
var properties = GetCachedProperties(typeof(T));
var list = new List();
foreach (DataRow row in dataTable.Rows)
{
var obj = new T();
foreach (var prop in properties)
{
if (!dataTable.Columns.Contains(prop.Key) || row[prop.Key] is DBNull) continue;
var value = Convert.ChangeType(row[prop.Key], prop.Value.PropertyType);
prop.Value.SetValue(obj, value);
}
list.Add(obj);
}
return list.ToArray();
}
/// 원본 객체 배열
/// 제네릭 객체 배열
public static T[] ToClass(this object[] srcArray) where T : class, new()
{
try
{
List list = new List();
var desProperties = GetCachedProperties(typeof(T));
foreach (object src in srcArray)
{
T des = new T();
list.Add(des);
var srcProperties = GetCachedProperties(src.GetType());
foreach (var srcProperty in srcProperties)
{
try
{
if (!desProperties.TryGetValue(srcProperty.Key, out var desProperty)) continue;
var srcValue = srcProperty.Value.GetValue(src);
if (srcProperty.Value.PropertyType != desProperty.PropertyType)
{
srcValue = Convert.ChangeType(srcValue, desProperty.PropertyType);
}
desProperty.SetValue(des, srcValue);
}
catch (Exception ex)
{
XLogger.Instance.Warn(ex);
}
}
}
return list.ToArray();
}
catch { throw; }
}
/// DataTable
/// List with generic objects
public static T ToClass(this object src) where T : class, new()
{
try
{
T des = new T();
var desProperties = GetCachedProperties(typeof(T));
var srcProperties = GetCachedProperties(src.GetType());
foreach (var srcProperty in srcProperties)
{
try
{
if (!desProperties.TryGetValue(srcProperty.Key, out var desProperty)) continue;
var srcValue = srcProperty.Value.GetValue(src);
if (srcProperty.Value.PropertyType != desProperty.PropertyType)
{
srcValue = Convert.ChangeType(srcValue, desProperty.PropertyType);
}
desProperty.SetValue(des, srcValue);
}
catch (Exception ex)
{
XLogger.Instance.Warn(ex);
}
}
return des;
}
catch { throw; }
}
#endregion
///
/// 객체의 메소드를 호출합니다.
///
///
///
///
///
public static object CallMethod(this object sender, string name, object[] parameters)
{
MethodInfo method = sender.GetType().GetMethod(name);
if (method == null) return false;
return method.Invoke(sender, parameters);
}
///
/// 객체의 속성 정보를 반환합니다.
///
///
///
public static string GetPropertiesString(this object sender)
{
try
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Type is {sender.GetType()}");
foreach (PropertyInfo property in sender.GetType().GetProperties())
{
try
{
sb.AppendLine($" > {property.Name} = {property.GetValue(sender)}");
}
catch
{
}
}
return sb.ToString();
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
throw ex;
}
}
///
/// 객체를 복제합니다.
///
///
///
///
public static T Clone(this T sender) where T : class, new()
{
T obj = new T();
try
{
sender.PropertiesCopy(obj);
return obj;
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
throw ex;
}
}
#region [ GetStringValue(Enum) ] --------------------------------------
///
/// Will get the string value for a given enums value, this will
/// only work if you assign the StringValue attribute to
/// the items in your enum.
///
///
///
public static string GetStringValue(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the stringvalue attributes
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(StringValueAttribute), false) as StringValueAttribute[];
// Return the first if there was a match.
return attribs.Length > 0 ? attribs[0].StringValue : null;
}
///
/// This attribute is used to represent a string value
/// for a value in an enum.
///
public class StringValueAttribute : Attribute
{
///
/// Holds the stringvalue for a value in an enum.
///
public string StringValue { get; protected set; }
///
/// Constructor used to init a StringValue Attribute
///
///
public StringValueAttribute(string value)
{
this.StringValue = value;
}
}
#endregion
///
/// GetDescription
///
///
///
///
public static string GetDescription(this T e) where T : IConvertible
{
if (e is Enum)
{
Type type = e.GetType();
Array values = Enum.GetValues(type);
foreach (int val in values)
{
if (val == e.ToInt32(CultureInfo.InvariantCulture))
{
var memInfo = type.GetMember(type.GetEnumName(val));
var descriptionAttribute = memInfo[0]
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.FirstOrDefault() as DescriptionAttribute;
if (descriptionAttribute != null)
{
return descriptionAttribute.Description;
}
}
}
}
return null;
}
public static CultureInfo CultureInfo { get; set; }
public static string ToTitleCase(this string sender)
{
if (ExtensionReflection.CultureInfo == null)
ExtensionReflection.CultureInfo = CultureInfo.CurrentCulture;
TextInfo textInfo = CultureInfo.TextInfo;
return textInfo.ToTitleCase(sender.ToLower());
}
public static Bitmap ControlCapture(this Control control, bool clipboard = true)
{
if (control == null) throw new ArgumentNullException("control");
Bitmap bitmap = new Bitmap(control.Width, control.Height);
control.DrawToBitmap(bitmap, new Rectangle(new Point(0, 0), control.Size));
if (clipboard) Clipboard.SetImage(bitmap);
return bitmap;
}
public static Bitmap ControlCapture(this Control control, Rectangle rect, bool clipboard = true)
{
if (control == null) throw new ArgumentNullException("control");
Bitmap bitmap = new Bitmap(rect.Width, rect.Height);
control.DrawToBitmap(bitmap, rect);
if (clipboard) Clipboard.SetImage(bitmap);
return bitmap;
}
///
/// 문자열을 열거형으로 반환한다
///
///
///
///
public static T ToEnum(this string sender, T value)
{
try
{
return (T)Enum.Parse(typeof(T), sender, true);
}
catch (Exception ex)
{
XLogger.Instance.Fatal(ex);
return value;
}
}
}
}