677 lines
21 KiB
C#
677 lines
21 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
|
|
namespace xCommons.Extensions
|
|
{
|
|
public static partial class ModelExtensions
|
|
{
|
|
/// <summary>
|
|
/// Retrieve a Binding Flag for Retrieve all Instance Members including
|
|
/// Priate and Public ...
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static BindingFlags GetDefaultBindingFlag()
|
|
{
|
|
return BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update an Instance of a Typed Object with Data Provided by another Instance of Typed Object
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="updateWith"></param>
|
|
/// <param name="propertyWhiteList"></param>
|
|
/// <param name="propertyBlackList"></param>
|
|
/// <param name="propertyValueProviders"></param>
|
|
/// <param name="updateWithNullOrEmptyValues"></param>
|
|
/// <param name="throwExceptionOnFails"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <typeparam name="D"></typeparam>
|
|
/// <returns></returns>
|
|
public static T UpdateData<T, D>(
|
|
this T source,
|
|
D updateWith,
|
|
ICollection<string> propertyWhiteList = null,
|
|
ICollection<string> propertyBlackList = null,
|
|
ICollection<KeyValuePair<string, Func<D, object>>> propertyValueProviders = null,
|
|
bool updateWithNullOrEmptyValues = false,
|
|
bool throwExceptionOnFails = false
|
|
)
|
|
where T : class
|
|
where D : class
|
|
{
|
|
//
|
|
var hasWhiteList = propertyWhiteList.HasChild<string>();
|
|
var hasBlackList = propertyBlackList.HasChild<string>();
|
|
var hasValueProvider = propertyValueProviders.HasChild<KeyValuePair<string, Func<D, object>>>();
|
|
|
|
//
|
|
var fullPropertyList = updateWith.GetType().GetProperties().Select(prop => prop.Name);
|
|
var mustSetProps = (hasWhiteList ? propertyWhiteList : fullPropertyList);
|
|
|
|
//
|
|
if (hasBlackList)
|
|
{
|
|
mustSetProps = mustSetProps.Where(propName => !propertyBlackList.Contains(propName));
|
|
}
|
|
|
|
//
|
|
mustSetProps.ToList().ForEach(propName =>
|
|
{
|
|
//
|
|
try
|
|
{
|
|
//
|
|
var sourceProp = source.GetType().GetProperty(propName);
|
|
var sourceValue = sourceProp.GetValue(source);
|
|
var sourceValueType = sourceValue.IsNull() ? null : sourceValue.GetType();
|
|
|
|
//
|
|
var updateWithProp = updateWith.GetType().GetProperty(propName);
|
|
var updateWithValue = updateWithProp.GetValue(updateWith);
|
|
var updateWithValueType = updateWithValue.IsNull() ? null : updateWithValue.GetType();
|
|
|
|
//
|
|
var valueProviderValue = hasValueProvider ? propertyValueProviders
|
|
.FirstOrDefault(p => p.Key == propName).Value : null;
|
|
var updateVal = !valueProviderValue.IsNull() ?
|
|
valueProviderValue.Invoke(updateWith) :
|
|
(updateWithValue.IsNull() && !updateWithNullOrEmptyValues) ?
|
|
sourceValue : updateWithValue;
|
|
var updateValType = updateVal.IsNull() ? null : updateVal.GetType();
|
|
|
|
//
|
|
Type t = Nullable.GetUnderlyingType(sourceProp.PropertyType) ?? sourceProp.PropertyType;
|
|
object safeValue =
|
|
(updateVal == null) ?
|
|
null :
|
|
!updateValType.IsCollectionType() ?
|
|
Convert.ChangeType(updateVal, t) :
|
|
updateVal;
|
|
|
|
//
|
|
sourceProp.SetValue(source, safeValue);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//
|
|
if (throwExceptionOnFails)
|
|
{
|
|
throw ex;
|
|
}
|
|
}
|
|
});
|
|
|
|
//
|
|
return source;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check a Class is Contains a Property or not ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="property"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static bool HasProperty<T>(
|
|
this T source,
|
|
string property,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
where T : class
|
|
{
|
|
//
|
|
var result = source
|
|
.GetType()
|
|
.GetProperties(bindingAttr)
|
|
.Any(prop => prop.Name == property); ;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check a Class is Contains a field or not ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="field"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static bool HasField<T>(
|
|
this T source,
|
|
string field,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
where T : class
|
|
{
|
|
//
|
|
var result = source
|
|
.GetType()
|
|
.GetFields(bindingAttr)
|
|
.Any(fld => fld.Name == field);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check a Class is Contains a Method or not ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="method"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static bool HasMethod<T>(
|
|
this T source,
|
|
string method,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
where T : class
|
|
{
|
|
//
|
|
var result = source
|
|
.GetType()
|
|
.GetMethods(bindingAttr)
|
|
.Any(mthd => mthd.Name == method);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve a Class Properties Names ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static string[] GetPropertiesNames<T>(
|
|
this T source,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
{
|
|
//
|
|
var result = source
|
|
.GetType()
|
|
.GetProperties(bindingAttr)
|
|
.Select(p => p.Name)
|
|
.ToArray();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve a Class Fields Names ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static string[] GetFieldsNames<T>(
|
|
this T source,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
{
|
|
//
|
|
var result = source
|
|
.GetType()
|
|
.GetFields(bindingAttr)
|
|
.Select(p => p.Name)
|
|
.ToArray();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve a Class Methods Names ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static string[] GetMethodsNames<T>(
|
|
this T source,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
{
|
|
//
|
|
var result = source
|
|
.GetType()
|
|
.GetMethods(bindingAttr)
|
|
.Select(p => p.Name)
|
|
.ToArray();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve a Class Members Names ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static string[] GetMembersNames<T>(
|
|
this T source,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
{
|
|
//
|
|
var result = source
|
|
.GetType()
|
|
.GetMembers(bindingAttr)
|
|
.Select(p => p.Name)
|
|
.ToArray();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a Class Property Value using Generic Concept ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <typeparam name="TProp"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="property"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static TProp GetProperty<T, TProp>(
|
|
this T source,
|
|
string property,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
where T : class
|
|
{
|
|
//
|
|
TProp result = default;
|
|
|
|
//
|
|
// Check if T Has Property ...
|
|
if (source.HasProperty(property))
|
|
{
|
|
//
|
|
// Access Property ...
|
|
var prop = source
|
|
.GetType()
|
|
.GetProperty(
|
|
property,
|
|
bindingAttr
|
|
);
|
|
|
|
//
|
|
// Retrieve Property Value as Object ...
|
|
var propVal = prop.GetValue(source);
|
|
|
|
//
|
|
result = (TProp)propVal;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a Class Field Value using Generic Concept ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <typeparam name="TField"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="field"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static TField GetField<T, TField>(
|
|
this T source,
|
|
string field,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
where T : class
|
|
{
|
|
//
|
|
TField result = default;
|
|
|
|
//
|
|
if (source.HasField(field))
|
|
{
|
|
//
|
|
var fld = source
|
|
.GetType()
|
|
.GetField(
|
|
field,
|
|
bindingAttr
|
|
);
|
|
|
|
//
|
|
var fieldVal = fld.GetValue(source);
|
|
result = (TField)fieldVal;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set a Class Property Value using Generic Concept ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <typeparam name="TProp"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="property"></param>
|
|
/// <param name="value"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static bool SetProperty<T, TProp>(
|
|
this T source,
|
|
string property,
|
|
TProp value,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
where T : class
|
|
{
|
|
//
|
|
// Check T Has Property ...
|
|
var result = source.HasProperty(property);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Access Property ...
|
|
var prop = source
|
|
.GetType()
|
|
.GetProperty(
|
|
property,
|
|
bindingAttr
|
|
);
|
|
|
|
//
|
|
// Set Property ...
|
|
try
|
|
{
|
|
//
|
|
result = true;
|
|
prop.SetValue(source, value);
|
|
}
|
|
catch
|
|
{
|
|
result = false;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set a Class Field Value using Generic Concept ...
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <typeparam name="TField"></typeparam>
|
|
/// <param name="source"></param>
|
|
/// <param name="field"></param>
|
|
/// <param name="value"></param>
|
|
/// <param name="bindingAttr"></param>
|
|
/// <returns></returns>
|
|
public static bool SetField<T, TField>(
|
|
this T source,
|
|
string field,
|
|
TField value,
|
|
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
)
|
|
where T : class
|
|
{
|
|
//
|
|
// Check T Has Field ...
|
|
var result = source.HasField(field);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Access Field ...
|
|
var fld = source
|
|
.GetType()
|
|
.GetField(
|
|
field,
|
|
bindingAttr
|
|
);
|
|
|
|
//
|
|
// Set Value ...
|
|
try
|
|
{
|
|
//
|
|
result = true;
|
|
fld.SetValue(source, value);
|
|
}
|
|
catch
|
|
{
|
|
result = false;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check two Instance of Typed Object Values are Same or not
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="dest"></param>
|
|
/// <param name="propertyWhiteList"></param>
|
|
/// <param name="propertyBlackList"></param>
|
|
/// <param name="throwExceptionOnFails"></param>
|
|
/// <param name="propertyValueCheckers"></param>
|
|
/// /// <typeparam name="T"></typeparam>
|
|
/// <typeparam name="D"></typeparam>
|
|
/// <returns></returns>
|
|
public static bool IsSameContent<T, D>(
|
|
this T source,
|
|
D dest,
|
|
ICollection<string> propertyWhiteList = null,
|
|
ICollection<string> propertyBlackList = null,
|
|
ICollection<KeyValuePair<string, Func<T, D, bool>>> propertyValueCheckers = null,
|
|
bool throwExceptionOnFails = false
|
|
)
|
|
where T : class
|
|
where D : class
|
|
{
|
|
//
|
|
var hasWhiteList = propertyWhiteList.HasChild<string>();
|
|
var hasBlackList = propertyBlackList.HasChild<string>();
|
|
var hasCheckerProvider = propertyValueCheckers.HasChild<KeyValuePair<string, Func<T, D, bool>>>();
|
|
|
|
//
|
|
var fullPropertyList = dest.GetType().GetProperties().Select(prop => prop.Name);
|
|
var mustCheckProps = (hasWhiteList ? propertyWhiteList : fullPropertyList);
|
|
if (hasBlackList)
|
|
{
|
|
mustCheckProps = mustCheckProps.Where(propName => !propertyBlackList.Contains(propName));
|
|
}
|
|
|
|
//
|
|
var result = true;
|
|
mustCheckProps.ToList().ForEach(propName =>
|
|
{
|
|
//
|
|
try
|
|
{
|
|
//
|
|
var sourceProp = source.GetType().GetProperty(propName);
|
|
var destProp = dest.GetType().GetProperty(propName);
|
|
|
|
//
|
|
// Check Types ...
|
|
var isSameType = true;
|
|
|
|
//
|
|
// Check
|
|
var isSameValue = false;
|
|
var mustDoCustomCheck = hasCheckerProvider && propertyValueCheckers.Any(p => p.Key == propName);
|
|
if (mustDoCustomCheck)
|
|
{
|
|
//
|
|
// Check Values ...
|
|
var valueChecker = propertyValueCheckers.FirstOrDefault(p => p.Key == propName).Value;
|
|
isSameValue = valueChecker.Invoke(source, dest);
|
|
}
|
|
else
|
|
{
|
|
// //
|
|
// isSameType = (sourceProp.PropertyType == destProp.PropertyType &&
|
|
// sourceProp.ReflectedType == destProp.ReflectedType);
|
|
|
|
//
|
|
// Check Values ...
|
|
isSameValue = Equals(sourceProp.GetValue(source), destProp.GetValue(dest));
|
|
}
|
|
|
|
//
|
|
if (!isSameType || !isSameValue)
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//
|
|
if (throwExceptionOnFails)
|
|
{
|
|
throw ex;
|
|
}
|
|
}
|
|
});
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check specific type is Collection Type or not
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <returns></returns>
|
|
public static bool IsCollectionType(this Type source)
|
|
{
|
|
//
|
|
if (source.IsNull() || !source.IsGenericType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
var genericTypeDefinition = source.GetGenericTypeDefinition();
|
|
var result = genericTypeDefinition == typeof(List<>) ||
|
|
genericTypeDefinition == typeof(HashSet<>) ||
|
|
genericTypeDefinition == typeof(Collection<>) ||
|
|
genericTypeDefinition == typeof(ICollection<>) ||
|
|
genericTypeDefinition == typeof(IEnumerable<>);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve a Property Value in Generic
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <returns></returns>
|
|
public static string GetPropValues<T>(this T item)
|
|
where T : class
|
|
{
|
|
//
|
|
var props = item.GetType().GetProperties();
|
|
var vals = props.Select(p => p.GetValue(item));
|
|
|
|
//
|
|
return vals.ToJSON();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check a Property Value Contains specific value
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <param name="value"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <returns></returns>
|
|
public static bool PropValuesContains<T>(this T item, string value)
|
|
where T : class
|
|
{
|
|
//
|
|
return item.GetPropValues()
|
|
.ToNormalString()
|
|
.Contains(value
|
|
.ToNormalString());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate Default Column Map
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <returns></returns>
|
|
public static IDictionary<string, Expression<Func<T, object>>> GetDefaultColumnsMap<T>(this T item)
|
|
where T : class
|
|
{
|
|
//
|
|
if (item.IsNull())
|
|
{
|
|
return null;
|
|
}
|
|
|
|
//
|
|
var result = new Dictionary<string, Expression<Func<T, object>>>();
|
|
var props = item.GetType().GetProperties();
|
|
|
|
//
|
|
foreach (var prop in props)
|
|
{
|
|
result.Add(prop.Name, t => t.GetType().GetProperty(prop.Name).GetValue(t, null));
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate Default Column Map
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <returns></returns>
|
|
public static IDictionary<string, string> GetPropValuesDictionary<T>(this T item)
|
|
where T : class
|
|
{
|
|
//
|
|
if (item.IsNull())
|
|
{
|
|
return null;
|
|
}
|
|
|
|
//
|
|
var result = new Dictionary<string, string>();
|
|
var props = item.GetType().GetProperties();
|
|
|
|
//
|
|
foreach (var prop in props)
|
|
{
|
|
result.Add(prop.Name, prop.GetValue(item).ToJSON());
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
}
|
|
} |