Background:
I am working with an organization that has an ever-growing collection of data types that they need to extract data from. I have no ability to change these data types. Some are machine-generated from XML files provided by other organizations; some are controlled by intransigent internal dev teams; and some are so old that no one is willing to change them in any way for fear that it will destabilize the entire Earth and cause it to crash into the sun. These classes don't share any common interface, and don't derive from any common type other than object. A few sample classes are given below for illustration purposes:
public class Untouchable
{
public string Data;
}
public class Unchangeable
{
public int Info;
}
The good news is that most of the time, I can use canned functionality to get at least some of the data from instances of the various classes. Unfortunately, most of these classes also have weird and specialized data that needs class-specific logic to extract data from. Also, information often needs to persist inside of the data extractors because the data objects I'm pulling data from have "interactions" (don't ask).
I have created an abstract generic Extractor<T> class to serve as a repository of common methodology, and an IExtractor<T> interface to serve as a convenient handle to access functionality. I also have a few specific (de-generic?) implementations of this class that can extract information from the business objects built from some of the data types. Here's some sample code to illustrate:
public interface IExtractor<T>
{
string ExtractionOne(T something);
string ExtractionTwo(T something);
}
public abstract class Extractor<T> : IExtractor<T>
{
private string internalInfo; // Certain business logic requires us to keep internal info over multiple objects that we extract data from.
protected Extractor() { internalInfo="stuff"; }
public virtual string ExtractionOne(T something)
{
return "This manipulation is generally applicable to most conceivable types.";
}
public abstract string ExtractionTwo(T something); // This DEFINITELY needs to be overridden for each class T
}
public class UntouchableExtractor : Extractor<Untouchable>
{
public UntouchableExtractor() : base() { }
public override string ExtractionTwo(Untouchable something)
{
return something.Data;
}
}
public class UnchangeableExtractor : Extractor<Unchangeable>
{
public UnchangeableExtractor() : base() { }
public override string ExtractionTwo(Unchangeable something)
{
return something.Info.ToString();
}
}
I don't yet support all of the available data types, but management wants to roll out the data extractor to end-users using a command-line interface. They're telling me that we should start extracting the data we can extract, and get to the rest later. Support for the many unmodifiable types will be added by me and by and other programmers as time permits, and the end-users are expected to work around our latency. This actually makes sense in our real-world setting, so just go with it.
The Problem:
The list of data types that we want to pull information from is very large. Maintaining an explicit list of supported types in code will be tricky and error prone -- especially if we find any problems with specific data extractors and need to revoke support until we fix some bugs.
I would like to support the large and changing list of supported data types from a single entry point that dynamically determines the "right version" of IExtractor<> to use based on a passed in dynamic dataObject. If there is no class that implements the IExtractor<> to support the given dataObject, than an error should be thrown.
What Doesn't Work:
I tried taking a dynamic thing and using typeof(Extractor<>).MakeGenericType(thing.GetType()) to create an instance of Extractor<Untouchable> or Extractor<Unchangeable>, but those are abstract classes, so I can't use Activator.CreateInstance() to build an instance of those classes. The core issue with this approach is that it's unfortunately looking for a class of the form Extractor<> instead of an interface of the form IExtractor<>.
I considered putting extension methods like IExtractor<T> BuildExtractor(this T something) in some class, but I'm nervous about running into some business logic called BuildExtractor that already exists in one of these untouchable classes. This may be an unhealthy level of paranoia, but that's where I'm at.
Where I need help:
I'd welcome any suggestions for how I can create a single entrypoint for an unconstrained collection of classes. Thanks in advance.
Combining some code from StackOverflow and my own testing, I suggest using Reflection to find all types implementing an interface:
public static class TypeExt {
public static bool IsBuiltin(this Type aType) => new[] { "/dotnet/shared/microsoft", "/windows/microsoft.net" }.Any(p => aType.Assembly.CodeBase.ToLowerInvariant().Contains(p));
public static IEnumerable<Type> ImplementingTypes(this Type interfaceType, bool includeAbstractClasses = false, bool includeStructs = false, bool includeSystemTypes = false, bool includeInterfaces = false) =>
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetLoadableTypes())
.Distinct()
.Where(aType => (includeAbstractClasses || !aType.IsAbstract) &&
(includeInterfaces ? aType != interfaceType : !aType.IsInterface) &&
(includeStructs || !aType.IsValueType) &&
(includeSystemTypes || !aType.IsBuiltin()) &&
interfaceType.IsAssignableFrom(aType) &&
aType.GetInterfaces().Contains(interfaceType));
}
public static class AssemblyExt {
//https://stackoverflow.com/a/29379834/2557128
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
if (assembly == null)
throw new ArgumentNullException("assembly");
try {
return assembly.GetTypes();
} catch (ReflectionTypeLoadException e) {
return e.Types.Where(t => t != null);
}
}
}
Reflection can be quite slow, and in my testing, getting all loaded types was the slowest part, so I added caching of the loaded types and the implementing types, but this does mean you will need to refresh the loaded types if you dynamically load assemblies:
public static class TypeExt {
public static bool IsBuiltin(this Type aType) => new[] { "/dotnet/shared/microsoft", "/windows/microsoft.net" }.Any(p => aType.Assembly.CodeBase.ToLowerInvariant().Contains(p));
static Dictionary<Type, HashSet<Type>> FoundTypes = null;
static List<Type> LoadableTypes = null;
public static void RefreshLoadableTypes() {
LoadableTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetLoadableTypes()).ToList();
FoundTypes = new Dictionary<Type, HashSet<Type>>();
}
public static IEnumerable<Type> ImplementingTypes(this Type interfaceType, bool includeAbstractClasses = false, bool includeStructs = false, bool includeSystemTypes = false, bool includeInterfaces = false) {
if (FoundTypes != null && FoundTypes.TryGetValue(interfaceType, out var ft))
return ft;
else {
if (LoadableTypes == null)
RefreshLoadableTypes();
var ans = LoadableTypes
.Where(aType => (includeAbstractClasses || !aType.IsAbstract) &&
(includeInterfaces ? aType != interfaceType : !aType.IsInterface) &&
(includeStructs || !aType.IsValueType) &&
(includeSystemTypes || !aType.IsBuiltin()) &&
interfaceType.IsAssignableFrom(aType) &&
aType.GetInterfaces().Contains(interfaceType))
.ToHashSet();
FoundTypes[interfaceType] = ans;
return ans;
}
}
}
public static class AssemblyExt {
//https://stackoverflow.com/a/29379834/2557128
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
if (assembly == null)
throw new ArgumentNullException("assembly");
try {
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e) {
return e.Types.Where(t => t != null);
}
}
}
Once you have one of these, you can make a factory method that takes a dynamic object:
public static class ImplementingFactory {
public static Type ExtractorType(dynamic anObject) {
Type oType = anObject.GetType();
var iType = typeof(IExtractor<>).MakeGenericType(oType);
var ans = iType.ImplementingTypes().FirstOrDefault();
if (ans == null)
throw new Exception($"Unable to find IExtractor<{oType.Name}>");
else
return ans;
}
}
The following snippet will create the concrete instance of Extractor<T> class and dynamically invokes a method of this instance
var test = new Unchangeable();
var baseType = typeof(Extractor<>).MakeGenericType(test.GetType());
var extractorType = Assembly.GetExecutingAssembly()
.GetTypes().FirstOrDefault(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(baseType));
if (extractorType != null)
{
dynamic extractor = Activator.CreateInstance(extractorType);
string result = extractor?.ExtractionTwo(test);
}
Of course, it's simplified, you can pass a specific instance of Unchangeable or Untouchable class and restrict assembly types scanning (and get all types only once).
The disadvantage here is that you have to pay attention to ExtractionOne and ExtractionTwo signatures, since they are invoked on dynamic object
The core issue with this approach is that it's unfortunately looking
for a class of the form Extractor<> instead of an interface of the
form IExtractor<>.
This snippet can help you to look through types using IExtrator<> interface
var baseType = typeof(IExtractor<>).MakeGenericType(typeof(Unchangeable));
var extractorType = Assembly.GetExecutingAssembly()
.GetTypes().FirstOrDefault(t => t.IsClass && !t.IsAbstract && baseType.IsAssignableFrom(t));
Related
I'm trying to create an AutoFixture.ICustomization that loops over every type that inherits from my model base and then explicitly doesn't assign any values to properties that also derive from that model base.
Obviously, this requires some serious abuse of reflection.
So far, I've got this:
public class DiscosModelFixtureCustomizationNoLinks: ICustomization
{
public void Customize(IFixture fixture)
{
Type[] discosModelTypes = typeof(DiscosModelBase).Assembly.GetTypes().Where(t => t.IsDiscosModel() && !t.IsAbstract).ToArray();
MethodInfo customizeMethod = fixture.GetType().GetMethods().Single(m => m.Name == nameof(fixture.Customize) && m.IsGenericMethod); // Needed to resolve overload with generic
foreach (Type t in discosModelTypes)
{
MethodInfo constructedCustomizeMethod = customizeMethod.MakeGenericMethod(t);
Type customizationComposer = typeof(ICustomizationComposer<>).MakeGenericType(t);
PropertyInfo[] propsToIgnore = t.GetProperties().Where(p => p.PropertyType.IsDiscosModel()).ToArray();
foreach (PropertyInfo prop in propsToIgnore)
{
// I want to essentially do this
// For every prop that derives from DiscosModelBase
// fixture.Customize<DiscosObject>(c => c.Without(p => p.Id));
// Using my constructed method
constructedCustomizeMethod.Invoke(fixture, new [] {myExpression});
}
}
}
}
So .Customize<T>() has this signature:
void Customize<T>(Func<ICustomizationComposer<T>, ISpecimenBuilder> composerTransformation);
And ICustomizationComposer<T>.Without() has this signature:
IPostprocessComposer<T> Without<TProperty>(Expression<Func<T, TProperty>> propertyPicker);
So essentially, I need to work out how to build the equivalent of c => c.Without(p => p.Id) using reflection and my PropertyInfo.
This answer would indicated that I can manually build the expression tree, however, it's not really explained in enough detail that I'm able to apply it in this context.
First up, is this possible? Secondly, if so, how do I accomplish this missing step?
So it seems as though I was massively overcomplicating this. Following some assistance from the dev behind AutoFixture, it's been made clear that what I'm trying to accomplish can be done through the use of an Omitter.
This Omitter requires a PropertySpecification which requires an instance of IEquatable<PropertyInfo> to tell it which properties to ignore.
So putting all of that together inside a customizer gives us:
public class DiscosModelFixtureCustomizationNoLinks: ICustomization
{
public void Customize(IFixture fixture)
{
var omitter = new Omitter(new PropertySpecification(new DiscosModelPropertyComparer()));
fixture.Customizations.Add(omitter);
}
private class DiscosModelPropertyComparer : IEquatable<PropertyInfo>
{
public bool Equals(PropertyInfo other) => other.PropertyType.IsDiscosModel();
}
}
For completeness, IsDiscosModel() is:
public static class TypeExtensions
{
public static bool IsDiscosModel(this Type t) =>
t.IsAssignableTo(typeof(DiscosModelBase)) ||
t.HasElementType && t.GetElementType()!.IsAssignableTo(typeof(DiscosModelBase)) ||
t.IsCollectionType() && t.IsGenericType && t.GetGenericArguments().Single().IsAssignableTo(typeof(DiscosModelBase));
}
Extra Info
It's worth noting that, while I didn't need it, the linked discussion shows how PropertySpecifications can be combined together with and and or statements to develop complex conditions for Omitters. For instance, if we take a type comparer that matches a given base type:
public class DeclaringTypeComparer : IEquatable<PropertyInfo>
{
public DeclaringTypeComparer(Type declaringType)
{
this.DeclaringType = declaringType;
}
public Type DeclaringType { get; }
public bool Equals(PropertyInfo other)
{
return other.DeclaringType == this.DeclaringType;
}
}
This can then be combined to ignore all properties inherited from base type and one specific property of a child type.
var spec = new OrRequestSpecification(
new PropertySpecification(new DeclaringTypeComparer(typeof(BaseType))),
new AndRequestSpecification(
new PropertySpecification(
new DeclaringTypeComparer(typeof(ChildType))),
new PropertySpecification(
new PropertyTypeAndNameCriterion(
new Criterion<Type>(typeof(IReadOnlyList<int>), EqualityComparer<Type>.Default),
new Criterion<string>("Numbers", StringComparer.Ordinal)))));
var omitter = new Omitter(spec);
var fixture = new Fixture();
fixture.Customizations.Insert(0, omitter);
I want to change my many if to a look-up table.
I have types and methods. I want to pair them.
if (propertyType == typeof(bool) || propertyType == typeof(bool?))
DoBool(propertyType);
if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
DoDateTime(propertyType);
if (propertyType == typeof(Guid) || propertyType == typeof(Guid?))
DoGuid(propertyType);
I have to create a Dictionary<Type, Action>()? Or which is the best elegant way to do this?
Can you offer me some suggestion where can I start or where can I find the solution?
Since this is more about controlling the flow of the code than pure lookup, I would probably use an object oriented approach and put the code for each "handler" inside separate classes (with common stuff inside a base class).
You can create a common interface like
public interface ITypeHandler {
void HandleType(Type type);
}
... and put the implementation of the handlers inside a dictionary of type Dictionary<Type, ITypeHandler> if you like, or you can have a property on the interface revealing which type it handles and select from a list of (perhaps Dependency Injected) handlers based on this property.
This adds benefits such as separation of concerns, testability, etc.
(Note that *Handler isn't a very good name, you will have to create a better name based on the scenario you're covering.)
You can create a Dictionary<Type, Action<Type>>:
var dict = new Dictionary<Type, Action<Type>>() {
{typeof(bool), DoBool},
{typeof(bool?), DoBool},
{typeof(DateTime), DoDateTime},
{typeof(Datetime?), DoDateTime},
{typeof(Guid), DoGuid},
{typeof(Guid?), DoGuid}
};
And then call it like this:
dict[propertyType](propertyType)
You could create a method for initializing your lookup table with the specified type, to avoid repeating.
private readonly IDictionary<Type, Action<Type>> _lookup;
then you can define method for initializing the _dict,
private void AddEntry<T>(Action<Type> action) where T : struct
{
_lookup[typeof(T)] = action;
_lookup[typeof(Nullable<T>)] = action;
}
private void DoInt(Type type) { /* implementation */ }
AddEntry<bool>(type => { /* implementation */ });
AddEntry<int>(DoInt);
I created my own implementation which is little bit different, but I used #DaggeJ suggestion, so thanks!
First I created a base handler class. After that I used this base on different type classes. You can see it below.
BaseClass:
public abstract class QueryHandler<T> where T : class
{
//I added here more property.
public abstract Type[] Types { get; }
protected QueryHandler(//Properties)
{
//Properties null check
}
public abstract IQueryable<T> Handle();
}
Descendant class:
internal class GuidQuery<T> : QueryHandler<T> where T : class
{
public override Type[] Types => new Type[] { typeof(Guid), typeof(Guid?) };
public GuidQuery(//Properties) : base(//Properties)
{
}
public override IQueryable<T> Handle()
{
// Implementation
}
}
Usage:
public IQueryable<T> GetQuery()
{
var queryHandlerList = new List<QueryHandler<T>>()
{
new IntQuery<T>(//Properties),
new DateTimeQuery<T>(//Properties),
new StringQuery<T>(//Properties),
new BoolQuery<T>(//Properties),
new GuidQuery<T>(//Properties),
new EnumQuery<T>(//Properties)
};
}
return query = queryHandlerList.FirstOrDefault(h => GetType<T>(h, property.PropertyType)).Handle();
private bool GetType<T>(QueryHandler<T> handler, Type type) where T: class
{
if (handler.Types.FirstOrDefault(t => t == type) == type || handler.Types.FirstOrDefault(t => t == type.BaseType) == type.BaseType) return true;
return false;
}
I'm trying to learn AutoFixture, and I've got xUnit and NSubstitute and AutoFixture setup to automatically mock out properties with fakes (with AutoFixture.AutoNSubstitute). In other words, if I have the following interface
public interface IFoo
{
IBar1 Bar1 {get;}
IBar2 Bar2 {get; set;}
}
Trying to resolve an IFoo will automatically resolve and populate Bar1 and Bar2.
Everything works great for objects with properties of interface, concrete object, or structure types. I'm having a problem getting AutoFixture to automatically create properties of abstract types however.
I have tried using a TypeRelay for the abstract type, so
fixture.Customizations.Add(new TypeRelay(typeof (AbstractBase), typeof (ConcreteChild)));
I have tried specifying it this way,
fixture.Customize<AbstractBase>(
composer =>
composer.FromFactory(
(string ChildParam1, string ChildParam2) => new ConcreteChild(ConcreteChildParam1, ConcreteChildParam2)));
I have tried using various custom specimen builders
Resolving via the property type:
var pi = request as PropertyInfo;
if (pi != null &&
pi.PropertyType == typeof(AbstractBase))
return context.Resolve(typeof(ConcreteChild));
return new NoSpecimen(request);
Resolving via the class type:
var pi = request as Type;
if (pi != null &&
pi == typeof (AbstractBase))
return context.Resolve(typeof(ConcreteChild));
return new NoSpecimen(request);
With both of the above solutions, I also tried context.Create<ConcreteChild>()
Finally I have tried using the Register<AbstractBase>(fixture.Create<ConcreteChild>); syntax.
None of them seem to work as far as automatically populating properties on an object.
The irritating thing is that I can explicitly fixture.Create<AbstractBase>(); in an individual test and get the ConcreteChild and then hand-jam everything but that kind of defeats the purpose of AutoFixture no?
Any ideas?
UPDATE:
The abstract class. I've pruned most of the irrelivent stuff, left the ctor code in as I'm assuming it gets called?
public abstract class ChatEntityId
{
private string _localName;
protected ChatEntityId(string chatRoomName, string entityUid, ChatProtocol protocol)
{
ErrorChecker.NormalizeToNullIfNotSet(ref chatRoomName);
ErrorChecker.NormalizeToNullIfNotSet(ref entityUid);
if (chatRoomName == null && entityUid == null)
{
throw new ArgumentException("Both chatRoomName and entityUid may not be null at the same time.");
}
ChatRoomName = chatRoomName;
EntityUid = entityUid;
Protocol = protocol;
}
public string ChatRoomName { get; private set; }
public string EntityUid { get; private set; }
public bool Equals(ChatEntityId chatEntityId) { }
public override bool Equals(object obj) { }
public override int GetHashCode() {}
public string LocalName { get; }
public ChatProtocol Protocol { get; private set; }
public override string ToString() { }
}
ChatProtocol is an enum, fairly standard.
The AutoPopulatedProperty ICustomization
public virtual void Customize(IFixture fixture)
{
fixture.Customize(new DomainCustomization());
// Replacement for the AutoNSubstituteCustomization, this Postprocessor will automatically create fake objects on properties.
fixture.ResidueCollectors.Add(
new Postprocessor(
new NSubstituteBuilder(
new MethodInvoker(
new NSubstituteMethodQuery())),
new AutoPropertiesCommand(
new PropertiesOnlySpecification())));
}
private class PropertiesOnlySpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
return request is PropertyInfo;
}
}
Somewhat embarrassingly, I realized that NSubstitute has what it calls recursive mocking, which is partially what I want and explains why I couldn't figure out where some of the auto-mocked properties were coming from. The problem is that it doesn't do it across the board (probably rightfully so), and isn't really extensible in that regard as far as I can tell.
Now AutoFixture comes into play, after we create the specimen in the Postprocessors NSubstituteBuilder, the AutoPropertiesCommand class is called and fetches what it determines are the appropriate properties to populate with data.
Unfortunately none of the logic in the two relevant classes (there is a non-generic inheriting from a generic AutoPropertiesCommand class) is overridable and this is where the problem occurs. Specifically, AutoPropertiesCommand<T> has two methods it uses to get properties and fields, which it then filters using the supplied IRequestSpecification (PropertiesOnlySpecification in this case).
The method in question
private IEnumerable<PropertyInfo> GetProperties(object specimen)
{
return from pi in this.GetSpecimenType(specimen).GetProperties(BindingFlags.Public | BindingFlags.Instance)
where pi.GetSetMethod() != null
&& pi.GetIndexParameters().Length == 0
&& this.specification.IsSatisfiedBy(pi)
select pi;
}
So the solution here is to either provide my own AutoPropertiesCommand implementation without the above limitations or explicitly create customizations for each case I run across. Haven't decided which approach I like better but probably the former.
As a side-bar it seems kind of restrictive to not have those two methods as protected virtual, is there any particular reason for this beyond "it was just coded that way"? Those are base AutoFixture classes I believe, for the record.
This question already has answers here:
How to find the minimum covariant type for best fit between two types?
(3 answers)
Closed 9 years ago.
Here're two extension methods for use
public static Type FindInterfaceWith(this Type type1, Type type2) {
// returns most suitable common implemented interface
}
public static Type FindBaseClassWith(this Type type1, Type type2) {
// returns most derivative of common base class
}
FindInterfaceWith returns null if they don't have common implemented interface.
FindBaseClassWith returns System.Object if they have no more derivative common base class.
FindBaseClassWith returns null if one of parameters was an interface.
Both they return null if any of parameter was null.
And the signature of method in finally solution would be like:
public static Type FindAssignableWith(this Type type1, Type type2) {
// what should be here?
}
Reflection and Linq are restricted to use, except there are no other way.
Are there good ways to find the best fit of common type between type1 and type2?
Or are there something better to achieve this?
update:
By my personal understanding, because of the ability to implement multiple interfaces with a class, the FindInterfaceWith could possibly need to call FindBaseClassWith internally; otherwise the best choice of type would be undecidable.
If this supposition was correct, then the FindInterfaceWith becomes a redundant method; because of the only difference between FindInterfaceWith and FindAssignableWith is:
FindInterfaceWith returns null if there was a best choice of class; while FindAssignableWith returns the exact class directly.
Otherwise, they both return a best choice of interface.
This is about saying the original assumption was irrational. That is, FindInterfaceWith cannot be implemented if FindAssignableWith is not.
Here is my implementation:
FindAssignableWith, FindBaseClassWith and FindInterfaceWith implementations
// provide common base class or implemented interface
public static Type FindAssignableWith(this Type typeLeft, Type typeRight)
{
if(typeLeft == null || typeRight == null) return null;
var commonBaseClass = typeLeft.FindBaseClassWith(typeRight) ?? typeof(object);
return commonBaseClass.Equals(typeof(object))
? typeLeft.FindInterfaceWith(typeRight)
: commonBaseClass;
}
// searching for common base class (either concrete or abstract)
public static Type FindBaseClassWith(this Type typeLeft, Type typeRight)
{
if(typeLeft == null || typeRight == null) return null;
return typeLeft
.GetClassHierarchy()
.Intersect(typeRight.GetClassHierarchy())
.FirstOrDefault(type => !type.IsInterface);
}
// searching for common implemented interface
// it's possible for one class to implement multiple interfaces,
// in this case return first common based interface
public static Type FindInterfaceWith(this Type typeLeft, Type typeRight)
{
if(typeLeft == null || typeRight == null) return null;
return typeLeft
.GetInterfaceHierarchy()
.Intersect(typeRight.GetInterfaceHierarchy())
.FirstOrDefault();
}
// iterate on interface hierarhy
public static IEnumerable<Type> GetInterfaceHierarchy(this Type type)
{
if(type.IsInterface) return new [] { type }.AsEnumerable();
return type
.GetInterfaces()
.OrderByDescending(current => current.GetInterfaces().Count())
.AsEnumerable();
}
// interate on class hierarhy
public static IEnumerable<Type> GetClassHierarchy(this Type type)
{
if(type == null) yield break;
Type typeInHierarchy = type;
do
{
yield return typeInHierarchy;
typeInHierarchy = typeInHierarchy.BaseType;
}
while(typeInHierarchy != null && !typeInHierarchy.IsInterface);
}
Remark regarding FindInterfaceWith implementation
Any interfaces that implements either IEnumerable or IEnumerable<T> will be selected before others, what I considered not to be correct
Open ended question of FindInterfaceWith
c# allow multiple interfaces to be implemented in one class, in this case first one of interfaces will be returned by FindInterfaceWith, because there is no way how to know which of interfaces IA or IB are preferable in general in following sample
Interfaces and classes hierarchy
public interface IBase {}
public interface ISomething {}
public interface IDerivied: IBase {}
public interface IDeriviedRight: IDerivied {}
public interface IDeriviedLeft: IDerivied, IDisposable {}
public class AnotherDisposable: IDisposable {
public void Dispose() {
}
}
public class DeriviedLeft: IDeriviedLeft {
public void Dispose() {
}
}
public class SubDeriviedLeft: DeriviedLeft {}
public class SecondSubDeriviedLeft: DeriviedLeft {}
public class ThirdSubDeriviedLeft: DeriviedLeft, ISomething {}
public class Another {}
public class DeriviedRight: IDeriviedRight {}
Test cases
And set of test cases using NUnit assertions:
FindBaseClassWith assertions example
// FindBaseClassWith returns null if one of parameters was an interface.
// FindBaseClassWith return null if any of parameter was null.
Assert.That(typeof(DeriviedLeft).FindBaseClassWith(typeof(DeriviedLeft)), Is.EqualTo(typeof(DeriviedLeft)));
FindInterfaceWith assertions example
// FindInterfaceWith returns null if they don't have common implemented interface.
// FindBaseClassWith return null if any of parameter was null.
Assert.That(typeof(DeriviedLeft).FindInterfaceWith(typeof(DeriviedLeft)), Is.EqualTo(typeof(IDeriviedLeft)));
FinAssignableWith assertions example
Assert.That(typeof(DeriviedLeft).FindAssignableWith(typeof(DeriviedLeft)), Is.SameAs(typeof(DeriviedLeft)));
Discussion at CodeReview
Review of this answer at codereview.stackexchange.com
ps:
Full sources available [here]
Oh, yay, I get to show off something I recently wrote for something else! :)
Caveat: This code is not the most efficient in the world, and it's VERY poorly commented - it was for a personal project, and I already knew how it worked - but I think it'll get you what you're after...
The method you'd be most interested in would be
public static Tuple<Type, IEnumerable<Type>> GetCommonBases(Type left, Type right)
The Tuple returned is <common base class, (list of common interfaces)>
A quick summary: this class, when given a type, does the following:
Reverse walks up the given type until it hits no more base types, pushing each into a 'working stack'
Pops each base type off the working stack, inserting it into a tree-like structure; If the type implements any interfaces, it adds nodes for those interface types as well
the helper method GetCommonBases creates one of these TypeTree structures for the first type, then 'merges' in the type tree for the other given type: it does so by walking down common base types until it finds a point where you have a common base type between the two types, at which point two branches of the tree are formed. It then "drills down" to each type from the root (i.e., System.Object), then finds the first point of deviation. The parent of this point of deviation is the Common base type.
The interfaces part relies on the definition of Interfaces, which "inherits" any Interface nodes for any ancestor. The GetCommonBases method pulls a list of any interfaces implemented by the two passed in types and returns an intersection of these two lists - that is, a set of interfaces that both passed in types implement.
the method then returns these two bits of information as a Tuple<Type, IEnumerable<Type>>, where the first item is the common base type, if any, and the second item is the intersection of common interfaces
public class TypeTree
{
private TypeTree()
{
Children = new List();
}
public TypeTree(Type value)
: this()
{
// Get to the basest class
var typeChain = GetTypeChain(value).ToList();
Value = typeChain.First();
foreach (var type in typeChain.Skip(1))
{
Add(type);
}
}
public Type Value { get; private set; }
public TypeTree Parent { get; private set; }
public List Children { get; private set; }
public IEnumerable Interfaces
{
get
{
var myInterfaces = Children.Where(c => c.Value.IsInterface);
return Parent == null ? myInterfaces : myInterfaces.Concat(Parent.Interfaces).Distinct();
}
}
public TypeTree Find(Type type)
{
if (Value == type)
return this;
return Children.Select(child => child.Find(type)).FirstOrDefault(found => found != null);
}
public TypeTree Add(Type type)
{
TypeTree retVal = null;
if (type.IsInterface)
{
if (Value.GetInterfaces().Contains(type))
{
retVal = new TypeTree { Value = type, Parent = this };
Children.Add(retVal);
return retVal;
}
}
var typeChain = GetTypeChain(type);
var walkTypes =
from baseType in typeChain
let alreadyExists = Value == baseType || Children.Any(c => c.Value == baseType)
where !alreadyExists
select baseType;
foreach (var baseType in walkTypes)
{
if (baseType.BaseType == Value)
{
// Add this as a child of the current tree
retVal = new TypeTree { Value = baseType, Parent = this };
Children.Add(retVal);
}
if (Value.IsAssignableFrom(baseType))
{
// we can add this as a child, potentially
retVal = Children.Aggregate(retVal, (current, child) => child.Add(baseType) ?? current);
}
// add interfaces
var interfaces = baseType.GetInterfaces().Where(i => i != type);
foreach (var intType in interfaces)
{
(retVal ?? this).Add(intType);
}
}
return retVal;
}
public override string ToString()
{
var childTypeNames = Children.Select(c => c.ToString()).Distinct();
return string.Format("({0} {1})", Value.Name, string.Join(" ", childTypeNames));
}
public static Tuple> GetCommonBases(Type left, Type right)
{
var tree = new TypeTree(left);
tree.Add(right);
var findLeft = tree.Find(left);
var findRight = tree.Find(right);
var commonInterfaces =
findLeft.Interfaces.Select(i => i.Value)
.Intersect(findRight.Interfaces.Select(i => i.Value))
.Distinct();
var leftStack = new Stack();
var temp = findLeft;
while (temp != null)
{
leftStack.Push(temp);
temp = temp.Parent;
}
var rightStack = new Stack();
temp = findRight;
while (temp != null)
{
rightStack.Push(temp);
temp = temp.Parent;
}
var zippedPaths = leftStack.Zip(rightStack, Tuple.Create);
var result = zippedPaths.TakeWhile(tup => tup.Item1.Value == tup.Item2.Value).Last();
return Tuple.Create(result.Item1.Value, commonInterfaces);
}
private static IEnumerable GetTypeChain(Type fromType)
{
var typeChain = new Stack();
var temp = fromType;
while (temp != null)
{
typeChain.Push(temp);
temp = temp.BaseType;
}
return typeChain;
}
}
I'll have a default implementation and some well-known classes and interface sorted by priority to have in mind. Here my implementation:
private static List<Type> CommonTypesPriorities = new List<Type>
{
typeof(IEnumerable),
typeof(Array),
typeof(IClonable)
};
public static Type FindAssignableWith(this Type type1, Type type2)
{
if(type1 == type2)
return type1;
var baseClass = type1.FindBaseClassWith(type2);
//if the base class is not object/null and it is not in the list, then return it.
if(baseClass != typeof(object) && baseClass != null && !CommonTypesPriorities.Contains(type))
return baseClass;
var #interface = type1.FindInterfaceWith(type2);
if(#interface == null)
return baseClase;
//if there's no base class and the found interface is not in the list, return it
if(baseClass != null && !CommonTypesPriorities.Contains(#interface)
return #interface;
//Now we have some class and interfaces from the list.
Type type = null;
int currentPriority;
//if the base class is in the list, then use it as the first choice
if(baseClass != null && CommonTypesPriorities.Contains(type))
{
type = baseClass;
currentPriority = CommonTypesPriorities.IndexOf(type);
}
var interfaces1 = type1.GetInterfaces();
var interfaces2 = type2.GetInterfaces();
foreach(var i in interfaces1)
{
if(interfaces2.Contains(i))
{
//We found a common interface. Let's check if it has more priority than the current one
var priority = CommonTypesPriorities.IndexOf(i);
if(i >= 0 && i < currentPriority)
{
currentPriority = priority;
type = i;
}
}
}
return type;
}
Hope it helps.
update +1: And now, without the stupid mistake and some more details
I suppose this is what you are looking for:
public static Type FindAssignableWith(this Type typeLeft, Type typeRight) {
if(typeLeft==null||typeRight==null)
return null;
var typeLeftUion=typeLeft.GetInterfaceHierarchy().Union(typeLeft.GetClassHierarchy());
var typeRightUion=typeRight.GetInterfaceHierarchy().Union(typeRight.GetClassHierarchy());
return
typeLeftUion.Intersect(typeRightUion)
.OrderByDescending(interfaceInHierarhy => interfaceInHierarhy.GetInterfaces().Contains(typeof(IEnumerable)))
.ThenByDescending(interfaceInHierarhy => interfaceInHierarhy.Equals(typeof(IEnumerable)))
.FirstOrDefault();
}
Basically it treats the base classes and interfaces the same in the ordering.
I suppose the base implementation is from [here].
What I did is basically glue the two methods together, without changing the semantics of the original functionality.
Example:
var result=typeof(char[]).FindAssignableWith2(typeof(string[]));
Console.WriteLine("{0}", typeof(char[]).FindAssignableWith2(typeof(string[]))); // IList
Console.WriteLine("{0}", typeof(Test).FindAssignableWith2(typeof(string[]))); // Object
// and so on...
I need some help figure out how to use reflection to get the concrete implementation based of the Dto type:
public interface IDocumentService<TDto>
{
}
public interface ICommentService: IDoumentService<CommentDto>
{
}
public abstract class DocumentService<TEntity,TDto>: IDocumentService<TDto> where TEntity: Entity, where TDto: Dto
{
}
public class CommentService: DocumentService<Comment,CommentDto>, ICommentService
{
}
So, what I want to do, is pass the CommentDto to a method so I can get to the CommentService.
public IDocumentService<TDto> GetDocumentService<TDto>()
{
//based on the TDto type I want to find the concrete that
//implements IDocumentService<TDto>
}
I would call it like this:
var commentDocumentService = GetDocumentService<CommentDto>();
So, I would get back CommentService, knowing that I would only see the methods part of the IDocumentService interface.
Here is a possible implementation for GetDocumentService.
public static IDocumentService<TDto> GetDocumentService<TDto>()
{
// Gets the type for IDocumentService
Type tDto=typeof(IDocumentService<TDto>);
Type tConcrete=null;
foreach(Type t in Assembly.GetExecutingAssembly().GetTypes()){
// Find a type that implements tDto and is concrete.
// Assumes that the type is found in the executing assembly.
if(tDto.IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface){
tConcrete=t;
break;
}
}
// Create an instance of the concrete type
object o=Activator.CreateInstance(tConcrete);
return (IDocumentService<TDto>)o;
}
It wasn't clear whether you wanted to return a new object, so I assumed so.
EDIT:
Due to your comment, here is a modified version of GetDocumentService. The disadvantage is that you need to specify another type parameter. The advantage, though, is that this approach provides a certain degree of type safety, since both type parameters must be compatible.
public static T GetDocumentService<TDto, T>() where T : IDocumentService<TDto>
{
// Gets the type for IDocumentService
Type tDto=typeof(T);
Type tConcrete=null;
foreach(Type t in Assembly.GetExecutingAssembly().GetTypes()){
// Find a type that implements tDto and is concrete.
// Assumes that the type is found in the calling assembly.
if(tDto.IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface){
tConcrete=t;
break;
}
}
// Create an instance of the concrete type
object o=Activator.CreateInstance(tConcrete);
return (T)o;
}
EDIT 2:
If I understand correctly, you want to get the other interfaces implemented by the type of the return value of GetDocumentService. For example, GetDocumentService<CommentDto> returns an object of type CommentService that implements the ICommentService interface. If I understand correctly, the return value should be a Type object (for example, the return value could be typeof(ICommentService)). Once you have the type, you should call the type's FullName property to get the type's name.
Use the following method on the return value of GetDocumentService to get the type of interface implemented by that value, for instance, typeof(ICommentService).
public static Type GetDocumentServiceType<TDto>(IDocumentService<TDto> obj){
Type tDto=typeof(IDocumentService<TDto>);
foreach(Type iface in obj.GetType().GetInterfaces()){
if(tDto.IsAssignableFrom(iface) && !iface.Equals(tDto)){
return iface;
}
}
return null;
}
Firstly, your CommentService class needs to be discoverable somehow, given the type of TDto. You can search all the loaded types from all the assemblies in the current AppDomain - however that will be painfully slow.
So you have the following viable options:
Use an attribute on the assembly that defines CommentService.
Use configuration to define this information.
Use MEF.
I'll demonstrate the first approach. Firstly create the attribute:
[AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = true)]
public sealed class DtoProviderAttribute : Attribute
{
public Type ProvidedType { get; private set; }
public Type ProviderType { get; private set; }
public DtoProviderAttribute(Type providedType, Type providerType)
{
ProvidedType = providedType;
ProviderType = providerType;
}
}
And then apply it to the assembly that defines CommentService (typically you would put in AssemblyInfo.cs).
[assembly:DtoProvider(typeof(CommentDto), typeof(CommentService))]
Now you can use those attributes to search for the concrete implementations.
public class ServiceFactory
{
private static readonly Dictionary<RuntimeTypeHandle, Func<object>> _dtoMappings = new Dictionary<RuntimeTypeHandle, Func<object>>();
public static IDocumentService<TDto> GetDocumentService<TDto>()
{
var rth = typeof(TDto).TypeHandle;
Func<object> concreteFactory;
lock (_dtoMappings)
{
if (_dtoMappings.TryGetValue(typeof(TDto).TypeHandle, out concreteFactory))
return (IDocumentService<TDto>)concreteFactory();
FillMappings();
if (!_dtoMappings.TryGetValue(typeof(TDto).TypeHandle, out concreteFactory))
throw new Exception("No concrete implementation found.");
return (IDocumentService<TDto>)concreteFactory();
}
}
private static void FillMappings()
{
// You would only need to change this method if you used the configuration-based approach.
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var attrs = assembly.GetCustomAttributes(typeof(DtoProviderAttribute), false);
foreach (DtoProviderAttribute item in attrs)
{
if (!_dtoMappings.ContainsKey(item.ProvidedType.TypeHandle))
{
var expr = Expression.Lambda<Func<object>>(Expression.Convert(Expression.New(item.ProviderType), typeof(object)));
_dtoMappings.Add(item.ProvidedType.TypeHandle, expr.Compile());
}
}
}
}
}
As 'Rune' pointed out: because of the cache the overhead of searching all the assemblies is low:
private static void FillMappings()
{
foreach (var type in AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).Where(x => x.IsClass && !x.IsAbstract))
{
foreach (var iface in type.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDocumentService<>)))
{
var arg = iface.GetGenericArguments()[0];
if (!_dtoMappings.ContainsKey(arg.TypeHandle))
{
var expr = Expression.Lambda<Func<object>>(Expression.Convert(Expression.New(type), typeof(object)));
_dtoMappings.Add(arg.TypeHandle, expr.Compile());
}
}
}
}
another possibility:
public IDocumentService<TDto> GetDocumentService<TDto>()
{
var genericParameter = typeof(TDto);
return (from type in Assembly.GetExecutingAssembly().GetTypes() // Get Types
where type.GetConstructor(Type.EmptyTypes) != null // That is concrete
let interfaces = type.GetInterfaces()
from intf in interfaces
where intf.IsGenericType // Which implement generic interface
let genarg = intf.GetGenericArguments()[0]
where genarg == genericParameter // Where generic argument is of type genericParameter
select (IDocumentService<TDto>) // Cast to IDocumentService
Activator.CreateInstance(type)).FirstOrDefault(); // Instantiate
}