This is a two-part question. First, which of these explicit property implementations gets bound to IAllTogether.SomeInt and why doesn't the compiler complain about ambiguity? It does when you comment-out the marked lines.
public interface IFirst
{
int SomeInt { get; }
}
public interface ISecond
{
int SomeInt { get; }
}
public interface ICombined : IFirst, ISecond
{
new int SomeInt { get; } // Comment this line.
}
public interface IAllTogether : IFirst, ISecond, ICombined
{ }
public sealed class Implementation : IAllTogether
{
int ICombined.SomeInt { get { return 0; } } // Comment this line.
int IFirst.SomeInt { get { return 0; } }
int ISecond.SomeInt { get { return 0; } }
}
IAllTogether t = new Implementation();
var unimportant = t.SomeInt;
Second question would be: how do I find the right PropertyInfo when given an interface Type and a name of the property? I can use GetInterfaces() and GetProperty() to list all the possible candidates, but how do I know which is the right one? I tried typeof(IAllTogether).GetProperty("SomeInt"), but it doesn't work.
Edit
Looks like the answer to the first part is that the hiding of inherited members resolves ambiguity. However, not even a single comment yet on the second part: how to reliably find the proper PropertyInfo for some property name and an interface type.
Edit 2
Clarification on the second part of the question. What I'm looking for is a way to get the right property for any unknown Type. Basically, a method like this:
public static PropertyInfo GetPropertyOfInterface(Type interfaceType, string propertyName)
{
if (!interfaceType.IsInterface)
throw new ArgumentException();
// for interfaceType == typeof(IAllTogether), return ICombined.SomeInt
// for interfaceType == typeof(IFirst), return IFirst.SomeInt
}
Lots of people answered the first part: if an interface hides members of the original interface, those are not considered.
Using that information, here's my attempt at the second part. Comments on issues or improvements are welcome.
public static PropertyInfo GetPropertyOfInterface(Type interfaceType, string propertyName)
{
if (interfaceType == null)
throw new ArgumentNullException("interfaceType");
if (!interfaceType.IsInterface)
throw new ArgumentException(
string.Format("Type {0} doesn't represent an interface.",
interfaceType.FullName),
"interfaceType");
// If declared in given interface, just return that.
var declaredProperty = interfaceType.GetProperty(propertyName);
if (declaredProperty != null)
return declaredProperty;
// Otherwise, first finding all the candidates.
var candidates = new HashSet<PropertyInfo>(
interfaceType.GetInterfaces().Select(t => t.GetProperty(propertyName)));
candidates.Remove(null);
if (candidates.Count == 0)
throw new ArgumentException(
string.Format("Property {0} not found in interface {1}.",
propertyName, interfaceType.FullName),
"propertyName");
// Finally, removing all candidates the first candidates hide.
var originalCandidates = candidates.ToList();
candidates.ExceptWith(
originalCandidates.SelectMany(prop => prop.DeclaringType.GetInterfaces())
.Select(t => t.GetProperty(propertyName)));
if (candidates.Count != 1)
throw new AmbiguousMatchException(
string.Format("Property {0} is ambiguous in interface {1}.",
propertyName, interfaceType.FullName));
return candidates.First();
}
To answer your first question.
Compiler only need to know is that the interface members are implemented or not. It is the runtime who decides which version of the member to invoke.
In your example you are using explicit implementation.
In this case compile first checks if SomeInt property is implemented or not. If that is implicitly implemented it won't complain. If any one of the interface property is implemented explicitly compiler will check if rest o the interface properties are implemented either by implicit or explicit.
Related
I have a class structure like the following
public Class A
{
public B b;
public C c;
public string strA;
}
public Class B
{
public D d;
public string strB;
}
public Class C
{
public string strC1;
public string strC2;
}
public Class D
{
public string strD1;
public string strD2;
}
For an object of class A,
A objA
I need to validate for example :
objA.b.strB
objA.b.D.strD2
objA.c.strC1
that they are nonempty strings. (Of course, it should be validated that the objects objA.b, objA.b.d and objA.c are not null)
I want to realize it with a method like
public bool ValidatePropertiesWithList(object obj, List<string> listOfFieldNamesToValidate, out string nameOfThePropertyThatViolatesTheValidation)
So I want to validate that the properties with the names in listOfFieldNamesToValidate are not empty, and return with an out parameter the name of the property (if any) that violates this.
Should I use Reflection to realize this validation or are Validation Attributes a better choice for me?
Using obj.GetType().GetProperties() seems to be a good place to start but I dont know how I can handle the hierarchical structure of the classes.
Is it possible to mark the properties of the classes with property attributes so that I can get rid of the listOfFieldNamesToValidate parameter in an elegant way?
Using a list of property names or Attributes solves very different problems:
A list of names should be used if its not known at compile time what properties should be validated; the caller is who knows and therefore its he who must supply the needed info.
Using Attributes necessarily means that someone knows at compile time the properties that need validation (this someone is, in the general case, not you; think in a plug-in scenario). Attributes are really handy to manage code scalability reducing dependencies and coupling; changing validation implementations when more classes, properties, validation rules, etc. appear can be very bug prone. Adding a simple Attribute to the new properties is relatively easy and hard to mess up.
Supposing the Attribute path is the one you really want, I've implemented a general case validator that does a couple of nifty things:
It automatically validates all properties marked with the specified Attribute.
It allows you to define validation rules for different property types.
It will not only match exact types, it will also use any valid reference conversions when searching for an applicable rule; for instance an object rule would be applied to a string property if no other rule with a more specific match is found. Note that this will not work with user defined implict conversions; an int rule will not be covered by a long rule and so on. This feature can be disabled.
I haven't tested this extensively but it should work reasonably well:
[AttributeUsage(AttributeTargets.Property)]
public class ValidateAttribute: Attribute
{
}
public class Validator<TAttribute> where TAttribute : Attribute
{
private readonly Dictionary<Type, Predicate<object>> rules;
public Validator()
{
rules = new Dictionary<Type, Predicate<object>>();
}
public bool UnregisterRule(Type t) => rules.Remove(t);
public void RegisterRule<TRule>(Predicate<TRule> rule) => rules.Add(typeof(TRule), o => rule((TRule)o));
public bool Validate<TTarget>(TTarget target, IList<string> failedValidationsBag, bool onlyExactTypeMatchRules = false)
{
var valid = true;
var properties = typeof(TTarget).GetProperties().Where(p => p.GetCustomAttribute<TAttribute>() != null);
foreach (var p in properties)
{
var value = p.GetValue(target);
Predicate<object> predicate = null;
//Rule aplicability works as follows:
//
//1. If the type of the property matches exactly the type of a rule, that rule is chosen and we are finished.
// If no exact match is found and onlyExactMatchRules is true no rule is chosen and we are finished.
//
//2. Build a candidate set as follows: If the type of a rule is assignable from the type of the property,
// add the type of the rule to the candidate set.
//
// 2.1.If the set is empty, no rule is chosen and we are finished.
// 2.2 If the set has only one candidate, the rule with that type is chosen and we're finished.
// 2.3 If the set has two or more candidates, keep the most specific types and remove the rest.
// The most specific types are those that are not assignable from any other type in the candidate set.
// Types are removed from the candidate set until the set either contains one single candidate or no more
// progress is made.
//
// 2.3.1 If the set has only one candidate, the rule with that type is chosen and we're finished.
// 2.3.2 If no more progress is made, we have an ambiguous rules scenario; there is no way to know which rule
// is better so an ArgumentException is thrown (this can happen for example when we have rules for two
// interfaces and an object subject to validation implements them both.)
Type ruleType = null;
if (!rules.TryGetValue(p.PropertyType, out predicate) && !onlyExactTypeMatchRules)
{
var candidateTypes = rules.Keys.Where(k => k.IsAssignableFrom(p.PropertyType)).ToList();
var count = candidateTypes.Count;
if (count > 0)
{
while (count > 1)
{
candidateTypes = candidateTypes.Where(type => candidateTypes.Where(otherType => otherType != type)
.All(otherType => !type.IsAssignableFrom(otherType)))
.ToList();
if (candidateTypes.Count == count)
throw new ArgumentException($"Ambiguous rules while processing {target}: {string.Join(", ", candidateTypes.Select(t => t.Name))}");
count = candidateTypes.Count;
}
ruleType = candidateTypes.Single();
predicate = rules[ruleType];
}
}
valid = checkRule(target, ruleType ?? p.PropertyType, value, predicate, p.Name, failedValidationsBag) && valid;
}
return valid;
}
private bool checkRule<T>(T target, Type ruleType, object value, Predicate<object> predicate, string propertyName, IList<string> failedValidationsBag)
{
if (predicate != null && !predicate(value))
{
failedValidationsBag.Add($"{target}: {propertyName} failed validation. [Rule: {ruleType.Name}]");
return false;
}
return true;
}
}
And you'd use it as follows:
public class Bar
{
public Bar(int value)
{
Value = value;
}
[Validate]
public int Value { get; }
}
public class Foo
{
public Foo(string someString, ArgumentException someArgumentExcpetion, Exception someException, object someObject, Bar someBar)
{
SomeString = someString;
SomeArgumentException = someArgumentExcpetion;
SomeException = someException;
SomeObject = someObject;
SomeBar = someBar;
}
[Validate]
public string SomeString { get; }
[Validate]
public ArgumentException SomeArgumentException { get; }
[Validate]
public Exception SomeException { get; }
[Validate]
public object SomeObject { get; }
[Validate]
public Bar SomeBar { get; }
}
static class Program
{
static void Main(string[] args)
{
var someObject = new object();
var someArgumentException = new ArgumentException();
var someException = new Exception();
var foo = new Foo("", someArgumentException, someException, someObject, new Bar(-1));
var validator = new Validator<ValidateAttribute>();
var bag = new List<string>();
validator.RegisterRule<string>(s => !string.IsNullOrWhiteSpace(s));
validator.RegisterRule<Exception>(exc => exc == someException);
validator.RegisterRule<object>(obj => obj == someObject);
validator.RegisterRule<int>(i => i > 0);
validator.RegisterRule<Bar>(b => validator.Validate(b, bag));
var valid = validator.Validate(foo, bag);
}
}
And of course, bag's content is the expected:
Foo: SomeString failed validation. [Rule: String]
Foo: SomeArgumentException failed validation. [Rule: Exception]
Bar: Value failed validation. [Rule: Int32]
Foo: SomeBar failed validation. [Rule: Bar]
I have a third-party, closed source application that exports a COM interface, which I am using in my C#.NET application through Interop. This COM interface exports many objects that all show up as System.Object until I cast them to the appropriate interface type. I want to assign an property of all of these objects. Thus:
foreach (object x in BigComInterface.Chickens)
{
(x as Chicken).attribute = value;
}
foreach (object x in BigComInterface.Ducks)
{
(x as Duck).attribute = value;
}
But assigning the property is likely (for application-specific reasons that are unavoidable) to throw Exceptions from which I want to recover, so I really want a try/catch around each one. Thus:
foreach (object x in BigComInterface.Chickens)
{
try
{
(x as Chicken).attribute = value;
}
catch (Exception ex)
{
// handle...
}
}
foreach (object x in BigComInterface.Ducks)
{
try
{
(x as Duck).attribute = value;
}
catch (Exception ex)
{
// handle...
}
}
Obviously, it would be so much cleaner to do this:
foreach (object x in BigComInterface.Chickens)
{
SetAttribute<Chicken>(x as Chicken, value);
}
foreach (object x in BigComInterface.Ducks)
{
SetAttribute<Duck>(x as Duck, value);
}
void SetAttribute<T>(T x, System.Object value)
{
try
{
x.attribute = value;
}
catch
{
// handle...
}
}
See the problem? My x value can be of any type, so the compiler can't resolve .attribute. Chicken and Duck are not in any kind of inheritance tree and they do not share an interface that has .attribute. If they did, I could put a constraint for that interface on T. But since the class is closed-source, that's not possible for me.
What I want, in my fantasy, is something like a constraint requiring the argument to have the .attribute property regardless of whether it implements a given interface. To wit,
void SetAttribute<T>(T x, System.Object value) where T:hasproperty(attribute)
I'm not sure what to do from here other than to cut/paste this little try/catch block for each of Chicken, Duck, Cow, Sheep, and so on.
My question is: What is a good workaround for this problem of wanting to invoke a specific property on an object when the interface that implements that property cannot be known at compile time?
Well, depending on how humongous your exception handling code is (and if i am not mistaken it could be quite so) using the following trick might help you:
class Chicken
{
public string attribute { get; set; }
}
class Duck
{
public string attribute { get; set; }
}
interface IHasAttribute
{
string attribute { get; set; }
}
class ChickenWrapper : IHasAttribute
{
private Chicken chick = null;
public string attribute
{
get { return chick.attribute; }
set { chick.attribute = value; }
}
public ChickenWrapper(object chick)
{
this.chick = chick as Chicken;
}
}
class DuckWrapper : IHasAttribute
{
private Duck duck = null;
public string attribute
{
get { return duck.attribute; }
set { duck.attribute = value; }
}
public DuckWrapper(object duck)
{
this.duck = duck as Duck;
}
}
void SetAttribute<T>(T x, string value) where T : IHasAttribute
{
try
{
x.attribute = value;
}
catch
{
// handle...
}
}
Unfortunately, this is tricky currently. In C# 4, the dynamic type may help quite a bit with this. COM interop is one of the places that dynamic really shines.
However, in the meantime, the only option that allows you to have any type of object, with no restrictions on interfaces, would be to revert to using reflection.
You can use reflection to find the "attribute" property, and set it's value at runtime.
To not have to violate the DRY principle you can use reflection. If you really want to use generics, you could use a wrapper class for each type of 3rd party object and have the wrapper implement an interface that you can use to constrain the generic type argument.
An example of how it could be done with reflection. Code is not tested though.
void SetAttribute(object chickenDuckOrWhatever, string attributeName, string value)
{
var typeOfObject = chickenDuckOrWhatever.GetType();
var property = typeOfObject.GetProperty(attributeName);
if (property != null)
{
property.SetValue(chickenDuckOrWhatever, value);
return;
}
//No property with this name was found, fall back to field
var field = typeOfObject.GetField(attributeName);
if (field == null) throw new Exception("No property or field was found on type '" + typeOfObject.FullName + "' by the name of '" + attributeName + "'.");
field.SetValue(chickenDuckOrWhatever, value);
}
If you to speed up the code for performance, you could cache the FieldInfo and PropertyInfo per type of chickenDuckOrWhatever and consult the dictionary first before reflecting.
TIP: To not have to hardcode the attributeName as a string, you could use C# 6 feature nameof. Like nameof(Chicken.AttributeName) for example.
Unfortunately the only way to do this is to constrain the type parameter with an interface that defines that property and is implemented on all types.
Since you do not have the source this will be impossible to implement and as such you will have to use some sort of workaround. C# is statically typed and as such doesn't support the kind of duck-typing you want to use here. The best thing coming soon (in C# 4) would be to type the object as dynamic and resolve the property calls at execution time (note that this approach would also not be generic as you cannot constrain a generic type parameter as dynamic).
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
}
I have a third-party, closed source application that exports a COM interface, which I am using in my C#.NET application through Interop. This COM interface exports many objects that all show up as System.Object until I cast them to the appropriate interface type. I want to assign an property of all of these objects. Thus:
foreach (object x in BigComInterface.Chickens)
{
(x as Chicken).attribute = value;
}
foreach (object x in BigComInterface.Ducks)
{
(x as Duck).attribute = value;
}
But assigning the property is likely (for application-specific reasons that are unavoidable) to throw Exceptions from which I want to recover, so I really want a try/catch around each one. Thus:
foreach (object x in BigComInterface.Chickens)
{
try
{
(x as Chicken).attribute = value;
}
catch (Exception ex)
{
// handle...
}
}
foreach (object x in BigComInterface.Ducks)
{
try
{
(x as Duck).attribute = value;
}
catch (Exception ex)
{
// handle...
}
}
Obviously, it would be so much cleaner to do this:
foreach (object x in BigComInterface.Chickens)
{
SetAttribute<Chicken>(x as Chicken, value);
}
foreach (object x in BigComInterface.Ducks)
{
SetAttribute<Duck>(x as Duck, value);
}
void SetAttribute<T>(T x, System.Object value)
{
try
{
x.attribute = value;
}
catch
{
// handle...
}
}
See the problem? My x value can be of any type, so the compiler can't resolve .attribute. Chicken and Duck are not in any kind of inheritance tree and they do not share an interface that has .attribute. If they did, I could put a constraint for that interface on T. But since the class is closed-source, that's not possible for me.
What I want, in my fantasy, is something like a constraint requiring the argument to have the .attribute property regardless of whether it implements a given interface. To wit,
void SetAttribute<T>(T x, System.Object value) where T:hasproperty(attribute)
I'm not sure what to do from here other than to cut/paste this little try/catch block for each of Chicken, Duck, Cow, Sheep, and so on.
My question is: What is a good workaround for this problem of wanting to invoke a specific property on an object when the interface that implements that property cannot be known at compile time?
Well, depending on how humongous your exception handling code is (and if i am not mistaken it could be quite so) using the following trick might help you:
class Chicken
{
public string attribute { get; set; }
}
class Duck
{
public string attribute { get; set; }
}
interface IHasAttribute
{
string attribute { get; set; }
}
class ChickenWrapper : IHasAttribute
{
private Chicken chick = null;
public string attribute
{
get { return chick.attribute; }
set { chick.attribute = value; }
}
public ChickenWrapper(object chick)
{
this.chick = chick as Chicken;
}
}
class DuckWrapper : IHasAttribute
{
private Duck duck = null;
public string attribute
{
get { return duck.attribute; }
set { duck.attribute = value; }
}
public DuckWrapper(object duck)
{
this.duck = duck as Duck;
}
}
void SetAttribute<T>(T x, string value) where T : IHasAttribute
{
try
{
x.attribute = value;
}
catch
{
// handle...
}
}
Unfortunately, this is tricky currently. In C# 4, the dynamic type may help quite a bit with this. COM interop is one of the places that dynamic really shines.
However, in the meantime, the only option that allows you to have any type of object, with no restrictions on interfaces, would be to revert to using reflection.
You can use reflection to find the "attribute" property, and set it's value at runtime.
To not have to violate the DRY principle you can use reflection. If you really want to use generics, you could use a wrapper class for each type of 3rd party object and have the wrapper implement an interface that you can use to constrain the generic type argument.
An example of how it could be done with reflection. Code is not tested though.
void SetAttribute(object chickenDuckOrWhatever, string attributeName, string value)
{
var typeOfObject = chickenDuckOrWhatever.GetType();
var property = typeOfObject.GetProperty(attributeName);
if (property != null)
{
property.SetValue(chickenDuckOrWhatever, value);
return;
}
//No property with this name was found, fall back to field
var field = typeOfObject.GetField(attributeName);
if (field == null) throw new Exception("No property or field was found on type '" + typeOfObject.FullName + "' by the name of '" + attributeName + "'.");
field.SetValue(chickenDuckOrWhatever, value);
}
If you to speed up the code for performance, you could cache the FieldInfo and PropertyInfo per type of chickenDuckOrWhatever and consult the dictionary first before reflecting.
TIP: To not have to hardcode the attributeName as a string, you could use C# 6 feature nameof. Like nameof(Chicken.AttributeName) for example.
Unfortunately the only way to do this is to constrain the type parameter with an interface that defines that property and is implemented on all types.
Since you do not have the source this will be impossible to implement and as such you will have to use some sort of workaround. C# is statically typed and as such doesn't support the kind of duck-typing you want to use here. The best thing coming soon (in C# 4) would be to type the object as dynamic and resolve the property calls at execution time (note that this approach would also not be generic as you cannot constrain a generic type parameter as dynamic).