Pool can now be used with types not derived from IRecyclable and/or without a public default constructor; consolidated type-related helper methods into a common helper class (TypeHelper.cs); optimized GetFieldInfosIncludingBaseClasses() method
git-svn-id: file:///srv/devel/repo-conversion/nusu@268 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
24439da822
commit
c91a082e84
|
@ -58,10 +58,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Source\Cloning\CloneFactoryTest.cs" />
|
<Compile Include="Source\Cloning\CloneFactoryTest.cs" />
|
||||||
<Compile Include="Source\Cloning\ClonerHelpers.cs" />
|
|
||||||
<Compile Include="Source\Cloning\ClonerHelpers.Test.cs">
|
|
||||||
<DependentUpon>ClonerHelpers.cs</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Source\Cloning\ExpressionTreeCloner.cs" />
|
<Compile Include="Source\Cloning\ExpressionTreeCloner.cs" />
|
||||||
<Compile Include="Source\Cloning\ExpressionTreeCloner.FieldBased.cs">
|
<Compile Include="Source\Cloning\ExpressionTreeCloner.FieldBased.cs">
|
||||||
<DependentUpon>ExpressionTreeCloner.cs</DependentUpon>
|
<DependentUpon>ExpressionTreeCloner.cs</DependentUpon>
|
||||||
|
@ -253,10 +249,6 @@
|
||||||
<Compile Include="Source\Plugins\NoPluginAttribute.Test.cs">
|
<Compile Include="Source\Plugins\NoPluginAttribute.Test.cs">
|
||||||
<DependentUpon>NoPluginAttribute.cs</DependentUpon>
|
<DependentUpon>NoPluginAttribute.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Plugins\PluginHelper.cs" />
|
|
||||||
<Compile Include="Source\Plugins\PluginHelper.Test.cs">
|
|
||||||
<DependentUpon>PluginHelper.cs</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Source\Plugins\PluginHost.cs" />
|
<Compile Include="Source\Plugins\PluginHost.cs" />
|
||||||
<Compile Include="Source\Plugins\PluginHost.Test.cs">
|
<Compile Include="Source\Plugins\PluginHost.Test.cs">
|
||||||
<DependentUpon>PluginHost.cs</DependentUpon>
|
<DependentUpon>PluginHost.cs</DependentUpon>
|
||||||
|
@ -285,6 +277,10 @@
|
||||||
<Compile Include="Source\ObservableHelper.Test.cs">
|
<Compile Include="Source\ObservableHelper.Test.cs">
|
||||||
<DependentUpon>ObservableHelper.cs</DependentUpon>
|
<DependentUpon>ObservableHelper.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Source\TypeHelper.cs" />
|
||||||
|
<Compile Include="Source\TypeHelper.Test.cs">
|
||||||
|
<DependentUpon>\TypeHelper.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Source\Semaphore.cs" />
|
<Compile Include="Source\Semaphore.cs" />
|
||||||
<Compile Include="Source\Semaphore.Test.cs">
|
<Compile Include="Source\Semaphore.Test.cs">
|
||||||
<DependentUpon>Semaphore.cs</DependentUpon>
|
<DependentUpon>Semaphore.cs</DependentUpon>
|
||||||
|
|
|
@ -89,10 +89,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Source\Cloning\CloneFactoryTest.cs" />
|
<Compile Include="Source\Cloning\CloneFactoryTest.cs" />
|
||||||
<Compile Include="Source\Cloning\ClonerHelpers.cs" />
|
|
||||||
<Compile Include="Source\Cloning\ClonerHelpers.Test.cs">
|
|
||||||
<DependentUpon>ClonerHelpers.cs</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Source\Cloning\ExpressionTreeCloner.cs" />
|
<Compile Include="Source\Cloning\ExpressionTreeCloner.cs" />
|
||||||
<Compile Include="Source\Cloning\ExpressionTreeCloner.FieldBased.cs">
|
<Compile Include="Source\Cloning\ExpressionTreeCloner.FieldBased.cs">
|
||||||
<DependentUpon>ExpressionTreeCloner.cs</DependentUpon>
|
<DependentUpon>ExpressionTreeCloner.cs</DependentUpon>
|
||||||
|
@ -284,10 +280,6 @@
|
||||||
<Compile Include="Source\Plugins\NoPluginAttribute.Test.cs">
|
<Compile Include="Source\Plugins\NoPluginAttribute.Test.cs">
|
||||||
<DependentUpon>NoPluginAttribute.cs</DependentUpon>
|
<DependentUpon>NoPluginAttribute.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Plugins\PluginHelper.cs" />
|
|
||||||
<Compile Include="Source\Plugins\PluginHelper.Test.cs">
|
|
||||||
<DependentUpon>PluginHelper.cs</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Source\Plugins\PluginHost.cs" />
|
<Compile Include="Source\Plugins\PluginHost.cs" />
|
||||||
<Compile Include="Source\Plugins\PluginHost.Test.cs">
|
<Compile Include="Source\Plugins\PluginHost.Test.cs">
|
||||||
<DependentUpon>PluginHost.cs</DependentUpon>
|
<DependentUpon>PluginHost.cs</DependentUpon>
|
||||||
|
@ -316,6 +308,10 @@
|
||||||
<Compile Include="Source\ObservableHelper.Test.cs">
|
<Compile Include="Source\ObservableHelper.Test.cs">
|
||||||
<DependentUpon>ObservableHelper.cs</DependentUpon>
|
<DependentUpon>ObservableHelper.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Source\TypeHelper.cs" />
|
||||||
|
<Compile Include="Source\TypeHelper.Test.cs">
|
||||||
|
<DependentUpon>\TypeHelper.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Source\Semaphore.cs" />
|
<Compile Include="Source\Semaphore.cs" />
|
||||||
<Compile Include="Source\Semaphore.Test.cs">
|
<Compile Include="Source\Semaphore.Test.cs">
|
||||||
<DependentUpon>Semaphore.cs</DependentUpon>
|
<DependentUpon>Semaphore.cs</DependentUpon>
|
||||||
|
|
|
@ -100,10 +100,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Source\Cloning\CloneFactoryTest.cs" />
|
<Compile Include="Source\Cloning\CloneFactoryTest.cs" />
|
||||||
<Compile Include="Source\Cloning\ClonerHelpers.cs" />
|
|
||||||
<Compile Include="Source\Cloning\ClonerHelpers.Test.cs">
|
|
||||||
<DependentUpon>ClonerHelpers.cs</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Source\Cloning\ExpressionTreeCloner.cs" />
|
<Compile Include="Source\Cloning\ExpressionTreeCloner.cs" />
|
||||||
<Compile Include="Source\Cloning\ExpressionTreeCloner.FieldBased.cs">
|
<Compile Include="Source\Cloning\ExpressionTreeCloner.FieldBased.cs">
|
||||||
<DependentUpon>ExpressionTreeCloner.cs</DependentUpon>
|
<DependentUpon>ExpressionTreeCloner.cs</DependentUpon>
|
||||||
|
@ -295,10 +291,6 @@
|
||||||
<Compile Include="Source\Plugins\NoPluginAttribute.Test.cs">
|
<Compile Include="Source\Plugins\NoPluginAttribute.Test.cs">
|
||||||
<DependentUpon>NoPluginAttribute.cs</DependentUpon>
|
<DependentUpon>NoPluginAttribute.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Source\Plugins\PluginHelper.cs" />
|
|
||||||
<Compile Include="Source\Plugins\PluginHelper.Test.cs">
|
|
||||||
<DependentUpon>PluginHelper.cs</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Source\Plugins\PluginHost.cs" />
|
<Compile Include="Source\Plugins\PluginHost.cs" />
|
||||||
<Compile Include="Source\Plugins\PluginHost.Test.cs">
|
<Compile Include="Source\Plugins\PluginHost.Test.cs">
|
||||||
<DependentUpon>PluginHost.cs</DependentUpon>
|
<DependentUpon>PluginHost.cs</DependentUpon>
|
||||||
|
@ -327,6 +319,10 @@
|
||||||
<Compile Include="Source\ObservableHelper.Test.cs">
|
<Compile Include="Source\ObservableHelper.Test.cs">
|
||||||
<DependentUpon>ObservableHelper.cs</DependentUpon>
|
<DependentUpon>ObservableHelper.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Source\TypeHelper.cs" />
|
||||||
|
<Compile Include="Source\TypeHelper.Test.cs">
|
||||||
|
<DependentUpon>\TypeHelper.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Source\Semaphore.cs" />
|
<Compile Include="Source\Semaphore.cs" />
|
||||||
<Compile Include="Source\Semaphore.Test.cs">
|
<Compile Include="Source\Semaphore.Test.cs">
|
||||||
<DependentUpon>Semaphore.cs</DependentUpon>
|
<DependentUpon>Semaphore.cs</DependentUpon>
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
#region CPL License
|
|
||||||
/*
|
|
||||||
Nuclex Framework
|
|
||||||
Copyright (C) 2002-2012 Nuclex Development Labs
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the IBM Common Public License as
|
|
||||||
published by the IBM Corporation; either version 1.0 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
IBM Common Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the IBM Common Public
|
|
||||||
License along with this library
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Nuclex.Support.Cloning {
|
|
||||||
|
|
||||||
/// <summary>Contains helper methods for the cloners</summary>
|
|
||||||
internal static class ClonerHelpers {
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all the fields of a type, working around a weird reflection issue
|
|
||||||
/// where explicitly declared fields in base classes are returned, but not
|
|
||||||
/// automatic property backing fields.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">Type whose fields will be returned</param>
|
|
||||||
/// <param name="bindingFlags">Binding flags to use when querying the fields</param>
|
|
||||||
/// <returns>All of the type's fields, including its base types</returns>
|
|
||||||
public static FieldInfo[] GetFieldInfosIncludingBaseClasses(
|
|
||||||
Type type, BindingFlags bindingFlags
|
|
||||||
) {
|
|
||||||
FieldInfo[] fieldInfos = type.GetFields(bindingFlags);
|
|
||||||
|
|
||||||
// If this class doesn't have a base, don't waste any time
|
|
||||||
if(type.BaseType == typeof(object)) {
|
|
||||||
return fieldInfos;
|
|
||||||
} else { // Otherwise, collect all types up to the furthest base class
|
|
||||||
var fieldInfoList = new List<FieldInfo>(fieldInfos);
|
|
||||||
while(type.BaseType != typeof(object)) {
|
|
||||||
type = type.BaseType;
|
|
||||||
fieldInfos = type.GetFields(bindingFlags);
|
|
||||||
|
|
||||||
// Look for fields we do not have listed yet and merge them into the main list
|
|
||||||
for(int index = 0; index < fieldInfos.Length; ++index) {
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
for(int searchIndex = 0; searchIndex < fieldInfoList.Count; ++searchIndex) {
|
|
||||||
bool match =
|
|
||||||
(fieldInfoList[searchIndex].DeclaringType == fieldInfos[index].DeclaringType) &&
|
|
||||||
(fieldInfoList[searchIndex].Name == fieldInfos[index].Name);
|
|
||||||
|
|
||||||
if(match) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!found) {
|
|
||||||
fieldInfoList.Add(fieldInfos[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fieldInfoList.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Cloning
|
|
|
@ -185,8 +185,8 @@ namespace Nuclex.Support.Cloning {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Enumerate all of the type's fields and generate transfer expressions for each
|
// Enumerate all of the type's fields and generate transfer expressions for each
|
||||||
FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
|
FieldInfo[] fieldInfos = clonedType.GetFieldInfosIncludingBaseClasses(
|
||||||
clonedType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
||||||
);
|
);
|
||||||
for(int index = 0; index < fieldInfos.Length; ++index) {
|
for(int index = 0; index < fieldInfos.Length; ++index) {
|
||||||
FieldInfo fieldInfo = fieldInfos[index];
|
FieldInfo fieldInfo = fieldInfos[index];
|
||||||
|
@ -495,8 +495,8 @@ namespace Nuclex.Support.Cloning {
|
||||||
ICollection<Expression> transferExpressions
|
ICollection<Expression> transferExpressions
|
||||||
) {
|
) {
|
||||||
// Enumerate all of the type's fields and generate transfer expressions for each
|
// Enumerate all of the type's fields and generate transfer expressions for each
|
||||||
FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
|
FieldInfo[] fieldInfos = clonedType.GetFieldInfosIncludingBaseClasses(
|
||||||
clonedType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
||||||
);
|
);
|
||||||
for(int index = 0; index < fieldInfos.Length; ++index) {
|
for(int index = 0; index < fieldInfos.Length; ++index) {
|
||||||
FieldInfo fieldInfo = fieldInfos[index];
|
FieldInfo fieldInfo = fieldInfos[index];
|
||||||
|
|
|
@ -167,8 +167,8 @@ namespace Nuclex.Support.Cloning {
|
||||||
object clone = FormatterServices.GetUninitializedObject(originalType);
|
object clone = FormatterServices.GetUninitializedObject(originalType);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
|
FieldInfo[] fieldInfos = originalType.GetFieldInfosIncludingBaseClasses(
|
||||||
originalType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
||||||
);
|
);
|
||||||
for(int index = 0; index < fieldInfos.Length; ++index) {
|
for(int index = 0; index < fieldInfos.Length; ++index) {
|
||||||
FieldInfo fieldInfo = fieldInfos[index];
|
FieldInfo fieldInfo = fieldInfos[index];
|
||||||
|
@ -249,8 +249,8 @@ namespace Nuclex.Support.Cloning {
|
||||||
object clone = FormatterServices.GetUninitializedObject(originalType);
|
object clone = FormatterServices.GetUninitializedObject(originalType);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
|
FieldInfo[] fieldInfos = originalType.GetFieldInfosIncludingBaseClasses(
|
||||||
originalType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
||||||
);
|
);
|
||||||
for(int index = 0; index < fieldInfos.Length; ++index) {
|
for(int index = 0; index < fieldInfos.Length; ++index) {
|
||||||
FieldInfo fieldInfo = fieldInfos[index];
|
FieldInfo fieldInfo = fieldInfos[index];
|
||||||
|
|
|
@ -118,8 +118,8 @@ namespace Nuclex.Support.Cloning {
|
||||||
) {
|
) {
|
||||||
Type originalType = objectToSerialize.GetType();
|
Type originalType = objectToSerialize.GetType();
|
||||||
|
|
||||||
FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
|
FieldInfo[] fieldInfos = originalType.GetFieldInfosIncludingBaseClasses(
|
||||||
originalType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
||||||
);
|
);
|
||||||
for(int index = 0; index < fieldInfos.Length; ++index) {
|
for(int index = 0; index < fieldInfos.Length; ++index) {
|
||||||
FieldInfo fieldInfo = fieldInfos[index];
|
FieldInfo fieldInfo = fieldInfos[index];
|
||||||
|
@ -143,8 +143,8 @@ namespace Nuclex.Support.Cloning {
|
||||||
) {
|
) {
|
||||||
Type originalType = deserializedObject.GetType();
|
Type originalType = deserializedObject.GetType();
|
||||||
|
|
||||||
FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
|
FieldInfo[] fieldInfos = originalType.GetFieldInfosIncludingBaseClasses(
|
||||||
originalType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
||||||
);
|
);
|
||||||
for(int index = 0; index < fieldInfos.Length; ++index) {
|
for(int index = 0; index < fieldInfos.Length; ++index) {
|
||||||
FieldInfo fieldInfo = fieldInfos[index];
|
FieldInfo fieldInfo = fieldInfos[index];
|
||||||
|
|
|
@ -30,8 +30,8 @@ namespace Nuclex.Support.Collections {
|
||||||
/// priority data type implements the IComparable interface, the user does not
|
/// priority data type implements the IComparable interface, the user does not
|
||||||
/// even
|
/// even
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class PairPriorityQueue<TPriority, TItem>
|
public class PairPriorityQueue<TPriority, TItem> :
|
||||||
: ICollection, IEnumerable<PriorityItemPair<TPriority, TItem>> {
|
ICollection, IEnumerable<PriorityItemPair<TPriority, TItem>> {
|
||||||
|
|
||||||
#region class PairComparer
|
#region class PairComparer
|
||||||
|
|
||||||
|
|
|
@ -98,13 +98,12 @@ namespace Nuclex.Support.Collections {
|
||||||
// starting from the last item in the assumption that this is the fastest
|
// starting from the last item in the assumption that this is the fastest
|
||||||
// way to empty a list without causing excessive shiftings in the array.
|
// way to empty a list without causing excessive shiftings in the array.
|
||||||
for(int index = base.Count - 1; index >= 0; --index) {
|
for(int index = base.Count - 1; index >= 0; --index) {
|
||||||
|
|
||||||
IDisposable disposable = base[index] as IDisposable;
|
IDisposable disposable = base[index] as IDisposable;
|
||||||
|
|
||||||
// If the item is disposable, destroy it now
|
// If the item is disposable, destroy it now
|
||||||
if(disposable != null)
|
if(disposable != null) {
|
||||||
disposable.Dispose();
|
disposable.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
base.ClearItems();
|
base.ClearItems();
|
||||||
|
|
|
@ -45,18 +45,35 @@ namespace Nuclex.Support.Collections {
|
||||||
/// automatically call its IRecyclable.Recycle() method.
|
/// automatically call its IRecyclable.Recycle() method.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class Pool<TItem> where TItem : class, new() {
|
public class Pool<TItem> {
|
||||||
|
|
||||||
/// <summary>Default number of recyclable objects the pool will store</summary>
|
/// <summary>Default number of recyclable objects the pool will store</summary>
|
||||||
public const int DefaultPoolSize = 64;
|
public const int DefaultPoolSize = 64;
|
||||||
|
|
||||||
/// <summary>Initializes a new pool using the default capacity</summary>
|
/// <summary>Initializes a new pool using the default capacity</summary>
|
||||||
public Pool() : this(DefaultPoolSize) { }
|
/// <param name="createNewDelegate">Delegate that will be used to create new items</param>
|
||||||
|
/// <param name="recycleDelegate">Delegate that will be used to recycle items</param>
|
||||||
|
public Pool(Func<TItem> createNewDelegate = null, Action<TItem> recycleDelegate = null) :
|
||||||
|
this(DefaultPoolSize, createNewDelegate, recycleDelegate) { }
|
||||||
|
|
||||||
/// <summary>Initializes a new pool using a user-specified capacity</summary>
|
/// <summary>Initializes a new pool using a user-specified capacity</summary>
|
||||||
/// <param name="capacity">Capacity of the pool</param>
|
/// <param name="capacity">Capacity of the pool</param>
|
||||||
public Pool(int capacity) {
|
/// <param name="createNewDelegate">Delegate that will be used to create new items</param>
|
||||||
|
/// <param name="recycleDelegate">Delegate that will be used to recycle items</param>
|
||||||
|
public Pool(
|
||||||
|
int capacity, Func<TItem> createNewDelegate = null, Action<TItem> recycleDelegate = null
|
||||||
|
) {
|
||||||
Capacity = capacity;
|
Capacity = capacity;
|
||||||
|
|
||||||
|
if(createNewDelegate == null) {
|
||||||
|
createNewDelegate = new Func<TItem>(Activator.CreateInstance<TItem>);
|
||||||
|
}
|
||||||
|
if(recycleDelegate == null) {
|
||||||
|
recycleDelegate = new Action<TItem>(callRecycleIfSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.createNewDelegate = createNewDelegate;
|
||||||
|
this.recycleDelegate = recycleDelegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -68,7 +85,7 @@ namespace Nuclex.Support.Collections {
|
||||||
if(this.items.Count > 0) {
|
if(this.items.Count > 0) {
|
||||||
return this.items.Dequeue();
|
return this.items.Dequeue();
|
||||||
} else {
|
} else {
|
||||||
return new TItem();
|
return this.createNewDelegate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,13 +99,14 @@ namespace Nuclex.Support.Collections {
|
||||||
// Call Recycle() when the object is redeemed (instead of when it leaves
|
// Call Recycle() when the object is redeemed (instead of when it leaves
|
||||||
// the pool again) in order to eliminate any references the object may hold
|
// the pool again) in order to eliminate any references the object may hold
|
||||||
// to other objects.
|
// to other objects.
|
||||||
callRecycleIfSupported(item);
|
this.recycleDelegate(item);
|
||||||
|
|
||||||
lock(this) {
|
lock(this) {
|
||||||
if(this.items.Count < this.capacity) {
|
if(this.items.Count < this.capacity) {
|
||||||
this.items.Enqueue(item);
|
this.items.Enqueue(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Number of objects the pool can retain</summary>
|
/// <summary>Number of objects the pool can retain</summary>
|
||||||
|
@ -125,6 +143,8 @@ namespace Nuclex.Support.Collections {
|
||||||
/// Required because the Queue class doesn't allow this value to be retrieved
|
/// Required because the Queue class doesn't allow this value to be retrieved
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private int capacity;
|
private int capacity;
|
||||||
|
private Func<TItem> createNewDelegate;
|
||||||
|
private Action<TItem> recycleDelegate;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Nuclex.Support.Plugins {
|
||||||
/// <param name="type">Type which will be assessed</param>
|
/// <param name="type">Type which will be assessed</param>
|
||||||
/// <returns>True if the type can be employed, otherwise false</returns>
|
/// <returns>True if the type can be employed, otherwise false</returns>
|
||||||
public virtual bool CanEmploy(Type type) {
|
public virtual bool CanEmploy(Type type) {
|
||||||
return PluginHelper.HasDefaultConstructor(type);
|
return type.HasDefaultConstructor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Employs the specified plugin type</summary>
|
/// <summary>Employs the specified plugin type</summary>
|
||||||
|
|
|
@ -24,7 +24,7 @@ using System.Collections.Generic;
|
||||||
namespace Nuclex.Support.Plugins {
|
namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
/// <summary>Employer to create factories of suiting types found in plugins</summary>
|
/// <summary>Employer to create factories of suiting types found in plugins</summary>
|
||||||
/// <typeparam name="ProductType">
|
/// <typeparam name="TProduct">
|
||||||
/// Interface or base class that the types need to implement
|
/// Interface or base class that the types need to implement
|
||||||
/// </typeparam>
|
/// </typeparam>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
|
@ -41,12 +41,12 @@ namespace Nuclex.Support.Plugins {
|
||||||
/// a human-readable name, capabilities or an icon.
|
/// a human-readable name, capabilities or an icon.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class FactoryEmployer<ProductType> : Employer where ProductType : class {
|
public class FactoryEmployer<TProduct> : Employer where TProduct : class {
|
||||||
|
|
||||||
#region class ConcreteFactory
|
#region class ConcreteFactory
|
||||||
|
|
||||||
/// <summary>Concrete factory for the types in a plugin assembly</summary>
|
/// <summary>Concrete factory for the types in a plugin assembly</summary>
|
||||||
private class ConcreteFactory : IAbstractFactory<ProductType>, IAbstractFactory {
|
private class ConcreteFactory : IAbstractFactory<TProduct>, IAbstractFactory {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a factory and configures it for the specified product
|
/// Initializes a factory and configures it for the specified product
|
||||||
|
@ -58,8 +58,8 @@ namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
/// <summary>Create a new instance of the type the factory is configured to</summary>
|
/// <summary>Create a new instance of the type the factory is configured to</summary>
|
||||||
/// <returns>The newly created instance</returns>
|
/// <returns>The newly created instance</returns>
|
||||||
public ProductType CreateInstance() {
|
public TProduct CreateInstance() {
|
||||||
return (ProductType)Activator.CreateInstance(this.concreteType);
|
return (TProduct)Activator.CreateInstance(this.concreteType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Create a new instance of the type the factory is configured to</summary>
|
/// <summary>Create a new instance of the type the factory is configured to</summary>
|
||||||
|
@ -77,11 +77,11 @@ namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
/// <summary>Initializes a new FactoryEmployer</summary>
|
/// <summary>Initializes a new FactoryEmployer</summary>
|
||||||
public FactoryEmployer() {
|
public FactoryEmployer() {
|
||||||
this.employedFactories = new List<IAbstractFactory<ProductType>>();
|
this.employedFactories = new List<IAbstractFactory<TProduct>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>List of all factories that the instance employer has created</summary>
|
/// <summary>List of all factories that the instance employer has created</summary>
|
||||||
public List<IAbstractFactory<ProductType>> Factories {
|
public List<IAbstractFactory<TProduct>> Factories {
|
||||||
get { return this.employedFactories; }
|
get { return this.employedFactories; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,20 +90,20 @@ namespace Nuclex.Support.Plugins {
|
||||||
/// <returns>True if the type can be employed</returns>
|
/// <returns>True if the type can be employed</returns>
|
||||||
public override bool CanEmploy(Type type) {
|
public override bool CanEmploy(Type type) {
|
||||||
return
|
return
|
||||||
PluginHelper.HasDefaultConstructor(type) &&
|
type.HasDefaultConstructor() &&
|
||||||
typeof(ProductType).IsAssignableFrom(type) &&
|
typeof(TProduct).IsAssignableFrom(type) &&
|
||||||
!type.ContainsGenericParameters;
|
!type.ContainsGenericParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Employs the specified plugin type</summary>
|
/// <summary>Employs the specified plugin type</summary>
|
||||||
/// <param name="type">Type to be employed</param>
|
/// <param name="type">Type to be employed</param>
|
||||||
public override void Employ(Type type) {
|
public override void Employ(Type type) {
|
||||||
if(!PluginHelper.HasDefaultConstructor(type)) {
|
if(!type.HasDefaultConstructor()) {
|
||||||
throw new MissingMethodException(
|
throw new MissingMethodException(
|
||||||
"Cannot employ type because it does not have a public default constructor"
|
"Cannot employ type because it does not have a public default constructor"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if(!typeof(ProductType).IsAssignableFrom(type)) {
|
if(!typeof(TProduct).IsAssignableFrom(type)) {
|
||||||
throw new InvalidCastException(
|
throw new InvalidCastException(
|
||||||
"Cannot employ type because it cannot be cast to the factory's product type"
|
"Cannot employ type because it cannot be cast to the factory's product type"
|
||||||
);
|
);
|
||||||
|
@ -118,7 +118,7 @@ namespace Nuclex.Support.Plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>All factories that the instance employer has created</summary>
|
/// <summary>All factories that the instance employer has created</summary>
|
||||||
private List<IAbstractFactory<ProductType>> employedFactories;
|
private List<IAbstractFactory<TProduct>> employedFactories;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ using System.Collections.Generic;
|
||||||
namespace Nuclex.Support.Plugins {
|
namespace Nuclex.Support.Plugins {
|
||||||
|
|
||||||
/// <summary>Employer that directly creates instances of the types in a plugin</summary>
|
/// <summary>Employer that directly creates instances of the types in a plugin</summary>
|
||||||
/// <typeparam name="T">Interface or base class required for the employed types</typeparam>
|
/// <typeparam name="TEmployedType">Interface or base class required for the employed types</typeparam>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// This employer directly creates an instance of any type in a plugin assembly that
|
/// This employer directly creates an instance of any type in a plugin assembly that
|
||||||
|
@ -44,15 +44,15 @@ namespace Nuclex.Support.Plugins {
|
||||||
/// factory would then be implemented on the plugin side.
|
/// factory would then be implemented on the plugin side.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class InstanceEmployer<T> : Employer {
|
public class InstanceEmployer<TEmployedType> : Employer {
|
||||||
|
|
||||||
/// <summary>Initializes a new instance employer</summary>
|
/// <summary>Initializes a new instance employer</summary>
|
||||||
public InstanceEmployer() {
|
public InstanceEmployer() {
|
||||||
this.employedInstances = new List<T>();
|
this.employedInstances = new List<TEmployedType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>All instances that have been employed</summary>
|
/// <summary>All instances that have been employed</summary>
|
||||||
public List<T> Instances {
|
public List<TEmployedType> Instances {
|
||||||
get { return this.employedInstances; }
|
get { return this.employedInstances; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,19 +61,19 @@ namespace Nuclex.Support.Plugins {
|
||||||
/// <returns>True if the type can be employed</returns>
|
/// <returns>True if the type can be employed</returns>
|
||||||
public override bool CanEmploy(Type type) {
|
public override bool CanEmploy(Type type) {
|
||||||
return
|
return
|
||||||
PluginHelper.HasDefaultConstructor(type) &&
|
type.HasDefaultConstructor() &&
|
||||||
typeof(T).IsAssignableFrom(type) &&
|
typeof(TEmployedType).IsAssignableFrom(type) &&
|
||||||
!type.ContainsGenericParameters;
|
!type.ContainsGenericParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Employs the specified plugin type</summary>
|
/// <summary>Employs the specified plugin type</summary>
|
||||||
/// <param name="type">Type to be employed</param>
|
/// <param name="type">Type to be employed</param>
|
||||||
public override void Employ(Type type) {
|
public override void Employ(Type type) {
|
||||||
this.employedInstances.Add((T)Activator.CreateInstance(type));
|
this.employedInstances.Add((TEmployedType)Activator.CreateInstance(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>All instances employed by the instance employer</summary>
|
/// <summary>All instances employed by the instance employer</summary>
|
||||||
private List<T> employedInstances;
|
private List<TEmployedType> employedInstances;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
#region CPL License
|
|
||||||
/*
|
|
||||||
Nuclex Framework
|
|
||||||
Copyright (C) 2002-2012 Nuclex Development Labs
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the IBM Common Public License as
|
|
||||||
published by the IBM Corporation; either version 1.0 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
IBM Common Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the IBM Common Public
|
|
||||||
License along with this library
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
#if UNITTEST
|
|
||||||
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace Nuclex.Support.Plugins {
|
|
||||||
|
|
||||||
/// <summary>Unit Test for the plugin helper class</summary>
|
|
||||||
[TestFixture]
|
|
||||||
internal class PluginHelperTest {
|
|
||||||
|
|
||||||
#region class NoDefaultConstructor
|
|
||||||
|
|
||||||
/// <summary>Test class that doesn't have a default constructor</summary>
|
|
||||||
private class NoDefaultConstructor {
|
|
||||||
/// <summary>Initializes a new instance of the test class</summary>
|
|
||||||
/// <param name="dummy">Dummy argument so this is no default constructor</param>
|
|
||||||
public NoDefaultConstructor(int dummy) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion // class NoDefaultConstructor
|
|
||||||
|
|
||||||
#region class NonPublicDefaultConstructor
|
|
||||||
|
|
||||||
/// <summary>Test class that has a non-public default constructor</summary>
|
|
||||||
private class NonPublicDefaultConstructor {
|
|
||||||
/// <summary>Initializes a new instance of the test class</summary>
|
|
||||||
protected NonPublicDefaultConstructor() { }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion // class NonPublicDefaultConstructor
|
|
||||||
|
|
||||||
#region class PublicDefaultConstructor
|
|
||||||
|
|
||||||
/// <summary>Test class that has a public default constructor</summary>
|
|
||||||
private class PublicDefaultConstructor {
|
|
||||||
/// <summary>Initializes a new instance of the test class</summary>
|
|
||||||
public PublicDefaultConstructor() { }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion // class PublicDefaultConstructor
|
|
||||||
|
|
||||||
/// <summary>Tests whether the default constructor detection works as expected</summary>
|
|
||||||
[Test]
|
|
||||||
public void TestDefaultConstructorDetection() {
|
|
||||||
Assert.IsFalse(
|
|
||||||
PluginHelper.HasDefaultConstructor(typeof(NoDefaultConstructor))
|
|
||||||
);
|
|
||||||
Assert.IsFalse(
|
|
||||||
PluginHelper.HasDefaultConstructor(typeof(NonPublicDefaultConstructor))
|
|
||||||
);
|
|
||||||
Assert.IsTrue(
|
|
||||||
PluginHelper.HasDefaultConstructor(typeof(PublicDefaultConstructor))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Plugins
|
|
||||||
|
|
||||||
#endif // UNITTEST
|
|
|
@ -1,44 +0,0 @@
|
||||||
#region CPL License
|
|
||||||
/*
|
|
||||||
Nuclex Framework
|
|
||||||
Copyright (C) 2002-2012 Nuclex Development Labs
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the IBM Common Public License as
|
|
||||||
published by the IBM Corporation; either version 1.0 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
IBM Common Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the IBM Common Public
|
|
||||||
License along with this library
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Nuclex.Support.Plugins {
|
|
||||||
|
|
||||||
/// <summary>Supporting functions for the plugin classes</summary>
|
|
||||||
public static class PluginHelper {
|
|
||||||
|
|
||||||
/// <summary>Determines whether the given type has a default constructor</summary>
|
|
||||||
/// <param name="type">Type which is to be checked</param>
|
|
||||||
/// <returns>True if the type has a default constructor</returns>
|
|
||||||
public static bool HasDefaultConstructor(Type type) {
|
|
||||||
ConstructorInfo[] constructors = type.GetConstructors();
|
|
||||||
|
|
||||||
foreach(ConstructorInfo constructor in constructors)
|
|
||||||
if(constructor.IsPublic && (constructor.GetParameters().Length == 0))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Plugins
|
|
|
@ -7,16 +7,16 @@ namespace Nuclex.Support.Plugins {
|
||||||
#if !NO_CLONING
|
#if !NO_CLONING
|
||||||
|
|
||||||
/// <summary>Factory that creates instances by cloning a prototype</summary>
|
/// <summary>Factory that creates instances by cloning a prototype</summary>
|
||||||
/// <typeparam name="ProductType">Type of product created by the factory</typeparam>
|
/// <typeparam name="TProduct">Type of product created by the factory</typeparam>
|
||||||
/// <typeparam name="ConcreteType">Type of the prototype that will be cloned</typeparam>
|
/// <typeparam name="TConcreteType">Type of the prototype that will be cloned</typeparam>
|
||||||
public class PrototypeFactory<ProductType, ConcreteType> :
|
public class PrototypeFactory<TProduct, TConcreteType> :
|
||||||
IAbstractFactory<ProductType>, IAbstractFactory, IDisposable
|
IAbstractFactory<TProduct>, IAbstractFactory, IDisposable
|
||||||
where ProductType : class
|
where TProduct : class
|
||||||
where ConcreteType : class, ICloneable {
|
where TConcreteType : class, ICloneable {
|
||||||
|
|
||||||
/// <summary>Initializes a new prototype based factory</summary>
|
/// <summary>Initializes a new prototype based factory</summary>
|
||||||
/// <param name="prototype">Prototype instance that will be cloned</param>
|
/// <param name="prototype">Prototype instance that will be cloned</param>
|
||||||
public PrototypeFactory(ConcreteType prototype) {
|
public PrototypeFactory(TConcreteType prototype) {
|
||||||
this.prototype = prototype;
|
this.prototype = prototype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@ namespace Nuclex.Support.Plugins {
|
||||||
/// Creates a new instance of the type to which the factory is specialized
|
/// Creates a new instance of the type to which the factory is specialized
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The newly created instance</returns>
|
/// <returns>The newly created instance</returns>
|
||||||
public ProductType CreateInstance() {
|
public TProduct CreateInstance() {
|
||||||
return (ProductType)this.prototype.Clone();
|
return (TProduct)this.prototype.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -49,7 +49,7 @@ namespace Nuclex.Support.Plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>The prototype object</summary>
|
/// <summary>The prototype object</summary>
|
||||||
private ConcreteType prototype;
|
private TConcreteType prototype;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,42 @@ using System.Reflection;
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace Nuclex.Support.Cloning {
|
namespace Nuclex.Support {
|
||||||
|
|
||||||
/// <summary>Unit Test for the cloner helpers</summary>
|
/// <summary>Unit Test for the strign segment class</summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
internal class ClonerHelpersTest {
|
internal class TypeHelperTest {
|
||||||
|
|
||||||
|
#region class NoDefaultConstructor
|
||||||
|
|
||||||
|
/// <summary>Test class that doesn't have a default constructor</summary>
|
||||||
|
private class NoDefaultConstructor {
|
||||||
|
/// <summary>Initializes a new instance of the test class</summary>
|
||||||
|
/// <param name="dummy">Dummy argument so this is no default constructor</param>
|
||||||
|
public NoDefaultConstructor(int dummy) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion // class NoDefaultConstructor
|
||||||
|
|
||||||
|
#region class NonPublicDefaultConstructor
|
||||||
|
|
||||||
|
/// <summary>Test class that has a non-public default constructor</summary>
|
||||||
|
private class NonPublicDefaultConstructor {
|
||||||
|
/// <summary>Initializes a new instance of the test class</summary>
|
||||||
|
protected NonPublicDefaultConstructor() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion // class NonPublicDefaultConstructor
|
||||||
|
|
||||||
|
#region class PublicDefaultConstructor
|
||||||
|
|
||||||
|
/// <summary>Test class that has a public default constructor</summary>
|
||||||
|
private class PublicDefaultConstructor {
|
||||||
|
/// <summary>Initializes a new instance of the test class</summary>
|
||||||
|
public PublicDefaultConstructor() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion // class PublicDefaultConstructor
|
||||||
|
|
||||||
#region class Base
|
#region class Base
|
||||||
|
|
||||||
|
@ -61,8 +92,8 @@ namespace Nuclex.Support.Cloning {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void CanGetBackingFieldsForPropertiesInBaseClasses() {
|
public void CanGetBackingFieldsForPropertiesInBaseClasses() {
|
||||||
FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
|
FieldInfo[] fieldInfos = typeof(Derived).GetFieldInfosIncludingBaseClasses(
|
||||||
typeof(Derived), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
|
||||||
);
|
);
|
||||||
Assert.AreEqual(4, fieldInfos.Length);
|
Assert.AreEqual(4, fieldInfos.Length);
|
||||||
}
|
}
|
||||||
|
@ -79,8 +110,16 @@ namespace Nuclex.Support.Cloning {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Tests whether the default constructor detection works as expected</summary>
|
||||||
|
[Test]
|
||||||
|
public void TestDefaultConstructorDetection() {
|
||||||
|
Assert.IsFalse(typeof(NoDefaultConstructor).HasDefaultConstructor());
|
||||||
|
Assert.IsFalse(typeof(NonPublicDefaultConstructor).HasDefaultConstructor());
|
||||||
|
Assert.IsTrue(typeof(PublicDefaultConstructor).HasDefaultConstructor());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Nuclex.Support.Cloning
|
} // namespace Nuclex.Support
|
||||||
|
|
||||||
#endif // UNITTEST
|
#endif // UNITTEST
|
147
Source/TypeHelper.cs
Normal file
147
Source/TypeHelper.cs
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
#region CPL License
|
||||||
|
/*
|
||||||
|
Nuclex Framework
|
||||||
|
Copyright (C) 2002-2012 Nuclex Development Labs
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the IBM Common Public License as
|
||||||
|
published by the IBM Corporation; either version 1.0 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
IBM Common Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the IBM Common Public
|
||||||
|
License along with this library
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Nuclex.Support {
|
||||||
|
|
||||||
|
/// <summary>Helper methods for the reflection Type class</summary>
|
||||||
|
public static class TypeHelper {
|
||||||
|
|
||||||
|
#region class MemberInfoComparer
|
||||||
|
|
||||||
|
/// <summary>Determines whether member informations relate to the same member</summary>
|
||||||
|
private class MemberInfoComparer : IEqualityComparer<MemberInfo> {
|
||||||
|
|
||||||
|
/// <summary>Default instance of the comparer</summary>
|
||||||
|
public static readonly MemberInfoComparer Default = new MemberInfoComparer();
|
||||||
|
|
||||||
|
/// <summary>Checks whether two member informations are equal</summary>
|
||||||
|
/// <param name="left">Informations about the left member in the comaprison</param>
|
||||||
|
/// <param name="right">Informations about the right member in the comparison</param>
|
||||||
|
/// <returns>True if the two member informations relate to the same member</returns>
|
||||||
|
public bool Equals(MemberInfo left, MemberInfo right) {
|
||||||
|
return
|
||||||
|
(left.DeclaringType == right.DeclaringType) &&
|
||||||
|
(left.Name == right.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Determines the hash code of the specified member informations</summary>
|
||||||
|
/// <param name="memberInfo">
|
||||||
|
/// Member informations whose hash code will be determined
|
||||||
|
/// </param>
|
||||||
|
/// <returns>The hash code of the specified member informations</returns>
|
||||||
|
public int GetHashCode(MemberInfo memberInfo) {
|
||||||
|
return (memberInfo.DeclaringType.GetHashCode() ^ memberInfo.Name.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion // class MemberInfoComparer
|
||||||
|
|
||||||
|
/// <summary>Determines whether the given type has a default constructor</summary>
|
||||||
|
/// <param name="type">Type which is to be checked</param>
|
||||||
|
/// <returns>True if the type has a default constructor</returns>
|
||||||
|
public static bool HasDefaultConstructor(this Type type) {
|
||||||
|
ConstructorInfo[] constructors = type.GetConstructors();
|
||||||
|
|
||||||
|
for(int index = 0; index < constructors.Length; ++index) {
|
||||||
|
ConstructorInfo constructor = constructors[index];
|
||||||
|
if(constructor.IsPublic && (constructor.GetParameters().Length == 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XBOX || WINDOWS_PHONE
|
||||||
|
/// <summary>
|
||||||
|
/// Returns all the fields of a type, including those defined in the type's base classes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">Type whose fields will be returned</param>
|
||||||
|
/// <param name="bindingFlags">Binding flags to use when querying the fields</param>
|
||||||
|
/// <returns>All of the type's fields, including its base types</returns>
|
||||||
|
public static FieldInfo[] GetFieldInfosIncludingBaseClasses(
|
||||||
|
this Type type, BindingFlags bindingFlags
|
||||||
|
) {
|
||||||
|
FieldInfo[] fieldInfos = type.GetFields(bindingFlags);
|
||||||
|
|
||||||
|
// If this class doesn't have a base, don't waste any time
|
||||||
|
if(type.BaseType != typeof(object)) {
|
||||||
|
var fieldInfoSet = new Dictionary<FieldInfo, object>(MemberInfoComparer.Default);
|
||||||
|
for(int index = 0; index < fieldInfos.Length; ++index) {
|
||||||
|
fieldInfoSet.Add(fieldInfos[index], null);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(type.BaseType != typeof(object)) {
|
||||||
|
type = type.BaseType;
|
||||||
|
fieldInfos = type.GetFields(bindingFlags);
|
||||||
|
|
||||||
|
for(int index = 0; index < fieldInfos.Length; ++index) {
|
||||||
|
FieldInfo fieldInfo = fieldInfos[index];
|
||||||
|
if(!fieldInfoSet.ContainsKey(fieldInfo)) {
|
||||||
|
fieldInfoSet.Add(fieldInfo, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldInfos = new FieldInfo[fieldInfoSet.Count];
|
||||||
|
fieldInfoSet.Keys.CopyTo(fieldInfos, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fieldInfos;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/// <summary>
|
||||||
|
/// Returns all the fields of a type, including those defined in the type's base classes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">Type whose fields will be returned</param>
|
||||||
|
/// <param name="bindingFlags">Binding flags to use when querying the fields</param>
|
||||||
|
/// <returns>All of the type's fields, including its base types</returns>
|
||||||
|
public static FieldInfo[] GetFieldInfosIncludingBaseClasses(
|
||||||
|
this Type type, BindingFlags bindingFlags
|
||||||
|
) {
|
||||||
|
FieldInfo[] fieldInfos = type.GetFields(bindingFlags);
|
||||||
|
|
||||||
|
// If this class doesn't have a base, don't waste any time
|
||||||
|
if(type.BaseType != typeof(object)) {
|
||||||
|
var fieldInfoSet = new HashSet<FieldInfo>(fieldInfos, MemberInfoComparer.Default);
|
||||||
|
while(type.BaseType != typeof(object)) {
|
||||||
|
type = type.BaseType;
|
||||||
|
fieldInfos = type.GetFields(bindingFlags);
|
||||||
|
for(int index = 0; index < fieldInfos.Length; ++index) {
|
||||||
|
fieldInfoSet.Add(fieldInfos[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldInfos = new FieldInfo[fieldInfoSet.Count];
|
||||||
|
fieldInfoSet.CopyTo(fieldInfos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fieldInfos;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Nuclex.Support
|
Loading…
Reference in New Issue
Block a user