MAJOR BREAKING CHANGE: Moved all extension methods for System.Object to Vanara.Extensions.Reflection namespace to avoid Intellisense overloads with methods that will be rarely used.

pull/83/head
David Hall 2019-08-17 14:42:49 -06:00
parent cb0adaf21a
commit ee72119e36
12 changed files with 163 additions and 138 deletions

View File

@ -4,72 +4,12 @@ using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace Vanara.Extensions
namespace Vanara.Extensions.Reflection
{
/// <summary>Extensions related to <c>System.Reflection</c></summary>
/// <summary>Extensions for <see cref="object"/> related to <c>System.Reflection</c></summary>
public static class ReflectionExtensions
{
private const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase;
private const BindingFlags staticBindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase;
/// <summary>For a structure, gets either the result of the static Create method or the default.</summary>
/// <typeparam name="T">The structure's type.</typeparam>
/// <returns>The result of the static Create method or the default.</returns>
public static T CreateOrDefault<T>() where T : struct
{
var mi = typeof(T).GetMethod("Create", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, Type.EmptyTypes, null);
return mi == null ? (default) : (T)mi.Invoke(null, null);
}
/// <summary>Gets all loaded types in the <see cref="AppDomain"/>.</summary>
/// <param name="appDomain">The application domain.</param>
/// <returns>All loaded types.</returns>
public static IEnumerable<Type> GetAllTypes(this AppDomain appDomain) => appDomain.GetAssemblies().SelectMany(a => a.GetTypes());
/// <summary>Returns an array of custom attributes applied to this member and identified by <typeparamref name="TAttr"/>.</summary>
/// <typeparam name="TAttr">The type of attribute to search for. Only attributes that are assignable to this type are returned.</typeparam>
/// <param name="element">An object derived from the MemberInfo class that describes a constructor, event, field, method, or property member of a class.</param>
/// <param name="inherit"><c>true</c> to search this member's inheritance chain to find the attributes; otherwise, <c>false</c>. This parameter is ignored for properties and events.</param>
/// <param name="predicate">An optional predicate to refine the results.</param>
/// <returns></returns>
public static IEnumerable<TAttr> GetCustomAttributes<TAttr>(this MemberInfo element, bool inherit = false, Func<TAttr, bool> predicate = null) where TAttr : Attribute =>
element.GetCustomAttributes(typeof(TAttr), inherit).Cast<TAttr>().Where(predicate ?? (a => true));
/// <summary>Returns an array of custom attributes applied to this member and identified by <typeparamref name="TAttr"/>.</summary>
/// <typeparam name="TAttr">The type of attribute to search for. Only attributes that are assignable to this type are returned.</typeparam>
/// <param name="type">The type of the <see cref="Type"/> to examine.</param>
/// <param name="inherit"><c>true</c> to search this member's inheritance chain to find the attributes; otherwise, <c>false</c>. This parameter is ignored for properties and events.</param>
/// <param name="predicate">An optional predicate to refine the results.</param>
/// <returns></returns>
public static IEnumerable<TAttr> GetCustomAttributes<TAttr>(this Type type, bool inherit = false, Func<TAttr, bool> predicate = null) where TAttr : Attribute =>
type.GetCustomAttributes(typeof(TAttr), inherit).Cast<TAttr>().Where(predicate ?? (a => true));
/// <summary>Finds the type of the element of a type. Returns null if this type does not enumerate.</summary>
/// <param name="type">The type to check.</param>
/// <returns>The element type, if found; otherwise, <see langword="null"/>.</returns>
public static Type FindElementType(this Type type)
{
if (type.IsArray)
return type.GetElementType();
// type is IEnumerable<T>;
if (ImplIEnumT(type))
return type.GetGenericArguments().First();
// type implements/extends IEnumerable<T>;
var enumType = type.GetInterfaces().Where(ImplIEnumT).Select(t => t.GetGenericArguments().First()).FirstOrDefault();
if (enumType != null)
return enumType;
// type is IEnumerable
if (IsIEnum(type) || type.GetInterfaces().Any(IsIEnum))
return typeof(object);
return null;
bool IsIEnum(Type t) => t == typeof(System.Collections.IEnumerable);
bool ImplIEnumT(Type t) => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>);
}
/// <summary>Gets a named field value from an object.</summary>
/// <typeparam name="T">The expected type of the field to be returned.</typeparam>
@ -83,16 +23,6 @@ namespace Vanara.Extensions
return (T)obj.GetType().InvokeMember(fieldName, BindingFlags.GetField | bindingFlags, null, obj, null, null);
}
/// <summary>Gets a named field value from an object.</summary>
/// <typeparam name="T">The expected type of the field to be returned.</typeparam>
/// <param name="fieldName">Name of the field.</param>
/// <returns>The field value.</returns>
public static T GetStaticFieldValue<T>(string fieldName)
{
if (string.IsNullOrEmpty(fieldName)) throw new ArgumentNullException(nameof(fieldName));
return (T)typeof(T).InvokeMember(fieldName, BindingFlags.GetField | staticBindingFlags, null, null, null);
}
/// <summary>Gets a named field value from an object.</summary>
/// <typeparam name="T">The expected type of the field to be returned.</typeparam>
/// <param name="obj">The object from which to retrieve the field.</param>
@ -148,31 +78,6 @@ namespace Vanara.Extensions
return gmi.Invoke(obj, args);
}
/// <summary>Invokes a named method on a created instance of a type with parameters.</summary>
/// <typeparam name="T">The expected type of the method's return value.</typeparam>
/// <param name="type">The type to be instantiated and then used to invoke the method. This method assumes the type has a default public constructor.</param>
/// <param name="methodName">Name of the method.</param>
/// <param name="args">The arguments to provide to the method invocation.</param>
/// <returns>The value returned from the method.</returns>
public static T InvokeMethod<T>(this Type type, string methodName, params object[] args)
{
var o = Activator.CreateInstance(type);
return InvokeMethod<T>(o, methodName, args);
}
/// <summary>Invokes a named method on a created instance of a type with parameters.</summary>
/// <typeparam name="T">The expected type of the method's return value.</typeparam>
/// <param name="type">The type to be instantiated and then used to invoke the method.</param>
/// <param name="instArgs">The arguments to supply to the constructor.</param>
/// <param name="methodName">Name of the method.</param>
/// <param name="args">The arguments to provide to the method invocation.</param>
/// <returns>The value returned from the method.</returns>
public static T InvokeMethod<T>(this Type type, object[] instArgs, string methodName, params object[] args)
{
var o = Activator.CreateInstance(type, instArgs);
return InvokeMethod<T>(o, methodName, args);
}
/// <summary>Invokes a named method on an object with parameters and no return value.</summary>
/// <param name="obj">The object on which to invoke the method.</param>
/// <param name="methodName">Name of the method.</param>
@ -226,6 +131,142 @@ namespace Vanara.Extensions
return (T)mi.Invoke(obj, args);
}
/// <summary>Sets a named field on an object.</summary>
/// <typeparam name="T">The type of the field to be set.</typeparam>
/// <param name="obj">The object on which to set the field.</param>
/// <param name="fieldName">Name of the field.</param>
/// <param name="value">The field value to set on the object.</param>
public static void SetFieldValue<T>(this object obj, string fieldName, T value)
{
try { obj?.GetType().InvokeMember(fieldName, BindingFlags.SetField | bindingFlags, null, obj, new object[] { value }, null); }
catch { }
}
/// <summary>Sets a named property on an object.</summary>
/// <typeparam name="T">The type of the property to be set.</typeparam>
/// <param name="obj">The object on which to set the property.</param>
/// <param name="propName">Name of the property.</param>
/// <param name="value">The property value to set on the object.</param>
public static void SetPropertyValue<T>(this object obj, string propName, T value)
{
try { obj?.GetType().InvokeMember(propName, BindingFlags.SetProperty | bindingFlags, null, obj, new object[] { value }, null); }
catch { }
}
}
}
namespace Vanara.Extensions
{
using Vanara.Extensions.Reflection;
/// <summary>Extensions related to <c>System.Reflection</c></summary>
public static class ReflectionExtensions
{
private const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase;
private const BindingFlags staticBindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase;
/// <summary>For a structure, gets either the result of the static Create method or the default.</summary>
/// <typeparam name="T">The structure's type.</typeparam>
/// <returns>The result of the static Create method or the default.</returns>
public static T CreateOrDefault<T>() where T : struct
{
var mi = typeof(T).GetMethod("Create", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, Type.EmptyTypes, null);
if (mi != null)
return (T)mi.Invoke(null, null);
var fi = typeof(T).GetField("Default", BindingFlags.Public | BindingFlags.Static);
if (fi != null)
return (T)fi.GetValue(null);
var pi = typeof(T).GetProperty("Default", BindingFlags.Public | BindingFlags.Static | BindingFlags.GetProperty, null, typeof(T), Type.EmptyTypes, null);
if (pi != null)
return (T)pi.GetValue(null);
return default;
}
/// <summary>Gets all loaded types in the <see cref="AppDomain"/>.</summary>
/// <param name="appDomain">The application domain.</param>
/// <returns>All loaded types.</returns>
public static IEnumerable<Type> GetAllTypes(this AppDomain appDomain) => appDomain.GetAssemblies().SelectMany(a => a.GetTypes());
/// <summary>Returns an array of custom attributes applied to this member and identified by <typeparamref name="TAttr"/>.</summary>
/// <typeparam name="TAttr">The type of attribute to search for. Only attributes that are assignable to this type are returned.</typeparam>
/// <param name="element">An object derived from the MemberInfo class that describes a constructor, event, field, method, or property member of a class.</param>
/// <param name="inherit"><c>true</c> to search this member's inheritance chain to find the attributes; otherwise, <c>false</c>. This parameter is ignored for properties and events.</param>
/// <param name="predicate">An optional predicate to refine the results.</param>
/// <returns></returns>
public static IEnumerable<TAttr> GetCustomAttributes<TAttr>(this MemberInfo element, bool inherit = false, Func<TAttr, bool> predicate = null) where TAttr : Attribute =>
element.GetCustomAttributes(typeof(TAttr), inherit).Cast<TAttr>().Where(predicate ?? (a => true));
/// <summary>Returns an array of custom attributes applied to this member and identified by <typeparamref name="TAttr"/>.</summary>
/// <typeparam name="TAttr">The type of attribute to search for. Only attributes that are assignable to this type are returned.</typeparam>
/// <param name="type">The type of the <see cref="Type"/> to examine.</param>
/// <param name="inherit"><c>true</c> to search this member's inheritance chain to find the attributes; otherwise, <c>false</c>. This parameter is ignored for properties and events.</param>
/// <param name="predicate">An optional predicate to refine the results.</param>
/// <returns></returns>
public static IEnumerable<TAttr> GetCustomAttributes<TAttr>(this Type type, bool inherit = false, Func<TAttr, bool> predicate = null) where TAttr : Attribute =>
type.GetCustomAttributes(typeof(TAttr), inherit).Cast<TAttr>().Where(predicate ?? (a => true));
/// <summary>Finds the type of the element of a type. Returns null if this type does not enumerate.</summary>
/// <param name="type">The type to check.</param>
/// <returns>The element type, if found; otherwise, <see langword="null"/>.</returns>
public static Type FindElementType(this Type type)
{
if (type.IsArray)
return type.GetElementType();
// type is IEnumerable<T>;
if (ImplIEnumT(type))
return type.GetGenericArguments().First();
// type implements/extends IEnumerable<T>;
var enumType = type.GetInterfaces().Where(ImplIEnumT).Select(t => t.GetGenericArguments().First()).FirstOrDefault();
if (enumType != null)
return enumType;
// type is IEnumerable
if (IsIEnum(type) || type.GetInterfaces().Any(IsIEnum))
return typeof(object);
return null;
bool IsIEnum(Type t) => t == typeof(System.Collections.IEnumerable);
bool ImplIEnumT(Type t) => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>);
}
/// <summary>Gets a named field value from an object.</summary>
/// <typeparam name="T">The expected type of the field to be returned.</typeparam>
/// <param name="fieldName">Name of the field.</param>
/// <returns>The field value.</returns>
public static T GetStaticFieldValue<T>(string fieldName)
{
if (string.IsNullOrEmpty(fieldName)) throw new ArgumentNullException(nameof(fieldName));
return (T)typeof(T).InvokeMember(fieldName, BindingFlags.GetField | staticBindingFlags, null, null, null);
}
/// <summary>Invokes a named method on a created instance of a type with parameters.</summary>
/// <typeparam name="T">The expected type of the method's return value.</typeparam>
/// <param name="type">The type to be instantiated and then used to invoke the method. This method assumes the type has a default public constructor.</param>
/// <param name="methodName">Name of the method.</param>
/// <param name="args">The arguments to provide to the method invocation.</param>
/// <returns>The value returned from the method.</returns>
public static T InvokeMethod<T>(this Type type, string methodName, params object[] args)
{
var o = Activator.CreateInstance(type);
return o.InvokeMethod<T>(methodName, args);
}
/// <summary>Invokes a named method on a created instance of a type with parameters.</summary>
/// <typeparam name="T">The expected type of the method's return value.</typeparam>
/// <param name="type">The type to be instantiated and then used to invoke the method.</param>
/// <param name="instArgs">The arguments to supply to the constructor.</param>
/// <param name="methodName">Name of the method.</param>
/// <param name="args">The arguments to provide to the method invocation.</param>
/// <returns>The value returned from the method.</returns>
public static T InvokeMethod<T>(this Type type, object[] instArgs, string methodName, params object[] args)
{
var o = Activator.CreateInstance(type, instArgs);
return o.InvokeMethod<T>(methodName, args);
}
/// <summary>Invokes a named static method of a type with parameters.</summary>
/// <typeparam name="T">The expected type of the method's return value.</typeparam>
/// <param name="type">The type containing the static method.</param>
@ -298,28 +339,6 @@ namespace Vanara.Extensions
return ret;
}
/// <summary>Sets a named field on an object.</summary>
/// <typeparam name="T">The type of the field to be set.</typeparam>
/// <param name="obj">The object on which to set the field.</param>
/// <param name="fieldName">Name of the field.</param>
/// <param name="value">The field value to set on the object.</param>
public static void SetFieldValue<T>(this object obj, string fieldName, T value)
{
try { obj?.GetType().InvokeMember(fieldName, BindingFlags.SetField | bindingFlags, null, obj, new object[] { value }, null); }
catch { }
}
/// <summary>Sets a named property on an object.</summary>
/// <typeparam name="T">The type of the property to be set.</typeparam>
/// <param name="obj">The object on which to set the property.</param>
/// <param name="propName">Name of the property.</param>
/// <param name="value">The property value to set on the object.</param>
public static void SetPropertyValue<T>(this object obj, string propName, T value)
{
try { obj?.GetType().InvokeMember(propName, BindingFlags.SetProperty | bindingFlags, null, obj, new object[] { value }, null); }
catch { }
}
/// <summary>Tries the retrieve a <see cref="Type"/> reference from an assembly.</summary>
/// <param name="typeName">Name of the type.</param>
/// <param name="asm">The assembly from which to load the type.</param>

View File

@ -705,12 +705,12 @@ namespace Vanara.PInvoke
break;
case DateTime dt:
pvFilter = new SYSTEMTIME(dt).StructureToPtr(Marshal.AllocCoTaskMem, out var _);
pvFilter = new SYSTEMTIME(dt).MarshalToPtr(Marshal.AllocCoTaskMem, out var _);
type = HeaderItemFilterType.HDFT_ISDATE;
break;
case string str:
pvFilter = new HDTEXTFILTER(str).StructureToPtr(Marshal.AllocCoTaskMem, out var _);
pvFilter = new HDTEXTFILTER(str).MarshalToPtr(Marshal.AllocCoTaskMem, out var _);
type = HeaderItemFilterType.HDFT_ISSTRING;
break;
@ -720,7 +720,7 @@ namespace Vanara.PInvoke
break;
case SYSTEMTIME st:
pvFilter = st.StructureToPtr(Marshal.AllocCoTaskMem, out var _);
pvFilter = st.MarshalToPtr(Marshal.AllocCoTaskMem, out var _);
type = HeaderItemFilterType.HDFT_ISDATE;
break;
@ -929,7 +929,7 @@ namespace Vanara.PInvoke
/// <param name="rc">The coordinates of the header.</param>
public HDLAYOUT(RECT rc)
{
prc = rc.StructureToPtr(Marshal.AllocHGlobal, out var _);
prc = rc.MarshalToPtr(Marshal.AllocHGlobal, out var _);
pwpos = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINDOWPOS)));
}
@ -941,7 +941,7 @@ namespace Vanara.PInvoke
set
{
Marshal.FreeHGlobal(prc);
prc = value.StructureToPtr(Marshal.AllocHGlobal, out var _);
prc = value.MarshalToPtr(Marshal.AllocHGlobal, out var _);
}
}

View File

@ -2159,14 +2159,12 @@ namespace Vanara.PInvoke
}
if (cColumns > 0)
{
puColumns = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int)) * (int)cColumns);
cols.MarshalToPtr(puColumns);
puColumns = cols.MarshalToPtr<int>(Marshal.AllocHGlobal, out _);
}
EnumExtensions.SetFlags(ref mask, ListViewItemMask.LVIF_COLUMNS);
if (hasFmts)
{
piColFmt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int)) * (int)cColumns);
fmts.MarshalToPtr(piColFmt);
piColFmt = fmts.MarshalToPtr<int>(Marshal.AllocHGlobal, out _);
EnumExtensions.SetFlags(ref mask, ListViewItemMask.LVIF_COLFMT);
}
}

View File

@ -2,6 +2,7 @@
using System.Runtime.InteropServices;
using System.Text;
using Vanara.Extensions;
using Vanara.Extensions.Reflection;
using Vanara.InteropServices;
namespace Vanara.PInvoke
@ -690,7 +691,7 @@ namespace Vanara.PInvoke
flags |= FormatMessageFlags.FORMAT_MESSAGE_IGNORE_INSERTS;
Win32Error lastError;
var buf = new StringBuilder(1024);
using (var pargs = new SafeHGlobalHandle(args.MarshalObjectsToPtr(Marshal.AllocHGlobal, out var sz, true), sz, true))
using (var pargs = new SafeHGlobalHandle(InteropExtensions.MarshalObjectsToPtr(args, Marshal.AllocHGlobal, out var sz, true), sz, true))
do
{
if (0 != FormatMessage(flags, hLib, id, langId, buf, (uint)buf.Capacity, (IntPtr)pargs))
@ -735,7 +736,7 @@ namespace Vanara.PInvoke
flags |= FormatMessageFlags.FORMAT_MESSAGE_IGNORE_INSERTS;
Win32Error lastError;
var buf = new StringBuilder(1024);
using (var pargs = new SafeHGlobalHandle(args.MarshalObjectsToPtr(Marshal.AllocHGlobal, out var sz, true), sz, true))
using (var pargs = new SafeHGlobalHandle(InteropExtensions.MarshalObjectsToPtr(args, Marshal.AllocHGlobal, out var sz, true), sz, true))
do
{
if (0 != FormatMessage(flags, formatString, 0, 0, buf, (uint)buf.Capacity, (IntPtr)pargs))

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,7 @@
using System;
using System.Linq;
using System.DirectoryServices.ActiveDirectory;
using Vanara.Extensions.Reflection;
using static Vanara.PInvoke.NTDSApi;
namespace Vanara.Extensions

View File

@ -1,4 +1,5 @@
using Vanara.Extensions;
using Vanara.Extensions.Reflection;
using NUnit.Framework;
using System;
using System.Drawing;
@ -109,7 +110,7 @@ namespace Vanara.Extensions.Tests
Assert.That(() => dt.InvokeMethod<long>("ToBin"), Throws.Exception);
Assert.That(() => dt.InvokeMethod<long>("ToBinary", 1), Throws.Exception);
Assert.That(() => dt.InvokeMethod<DateTime>("ToBinary", 1), Throws.Exception);
Assert.That(() => dt.InvokeMethod<TimeSpan>("Subtract", new[] {typeof(long)}, new object[] {1}), Throws.ArgumentException);
Assert.That(() => dt.InvokeMethod<TimeSpan>("Subtract", new[] { typeof(long) }, new object[] { 1 }), Throws.ArgumentException);
Assert.That(() => dt.InvokeMethod<TimeSpan>("Subtract", new[] { typeof(DateTime) }, new object[] { 1 }), Throws.ArgumentException);
Assert.That(() => dt.InvokeMethod<long>("Subtract", new[] { typeof(DateTime) }, new object[] { DateTime.Now }), Throws.ArgumentException);
}

View File

@ -4,6 +4,7 @@ using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using Vanara.Extensions;
using Vanara.Extensions.Reflection;
namespace Vanara.Configuration
{
@ -495,7 +496,7 @@ namespace Vanara.Windows.Forms
/// <param name="onRecentFileClick">Action to run when The on recent file click.</param>
/// <param name="onClearRecentFilesClick">Optional. The on clear recent files click.</param>
/// <param name="storageHandler">Optional. The storage handler.</param>
public MenuStripMRUManager(string extensions, ToolStripMenuItem parentMenuItem, Action<string> onRecentFileClick,
public MenuStripMRUManager(string extensions, ToolStripMenuItem parentMenuItem, Action<string> onRecentFileClick,
Action<StringCollection> onClearRecentFilesClick = null, IFileListStorage storageHandler = null)
: base(storageHandler ?? new AppSettingsFileListStorage(), new MenuStripMenuBuilder())
{
@ -571,7 +572,7 @@ namespace Vanara.Windows.Forms
if (!string.IsNullOrEmpty(clearListMenuItemText))
{
RecentFileMenuItem.DropDownItems.Add("-");
RecentFileMenuItem.DropDownItems.Add(clearListMenuItemText, null, (o, e) => clearListMenuItemClick?.Invoke() );
RecentFileMenuItem.DropDownItems.Add(clearListMenuItemText, null, (o, e) => clearListMenuItemClick?.Invoke());
}
RecentFileMenuItem.Enabled = true;
}

View File

@ -2,6 +2,7 @@
using System.Reflection;
using System.Security.AccessControl;
using Vanara.Extensions;
using Vanara.Extensions.Reflection;
namespace Vanara.Security.AccessControl
{

View File

@ -1,5 +1,6 @@
using System.Drawing;
using System.Windows.Forms;
using Vanara.Extensions.Reflection;
namespace Vanara.Extensions
{

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Vanara.Extensions;
using Vanara.Extensions.Reflection;
using Vanara.PInvoke;
using static Vanara.PInvoke.Ole32;

View File

@ -1,6 +1,6 @@
using System;
using System.Runtime.InteropServices;
using Vanara.Extensions;
using Vanara.Extensions.Reflection;
using Vanara.PInvoke;
using static Vanara.PInvoke.Ole32;