What is the correct way to check that a given property info is an implementation of a property from an interface?
There is a class InterfaceMap that solve this problem for methods. But for properties, it provides two separate mappings for getter and setter and there still remains a problem to match those with the corresponding interface methods.
public interface IA
{
int X { get; set; }
}
public interface IB
{
int X { get; set; }
}
public class C : IA, IB
{
public int X { get; set; }
int IB.X { get; set; }
}
public PropertyInfo GetProperty<TClass, TProperty>(Expression<Func<TClass, TProperty>> getProperty)
{
return (PropertyInfo)((MemberExpression)getProperty.Body).Member;
}
[Test]
public void Check()
{
var aProperty = GetProperty((IA x) => x.X);
var bProperty = GetProperty((IB x) => x.X);
var cPropertyA = GetProperty((C x) => x.X);
var cPropertyB = GetProperty((C x) => ((IB)x).X);
CompareProperties(cPropertyA, aProperty); // True
CompareProperties(cPropertyA, bProperty); // False
CompareProperties(cPropertyB, aProperty); // False
CompareProperties(cPropertyB, bProperty); // True
}
private bool CompareProperties(PropertyInfo classProperty, PropertyInfo interfaceProperty)
{
// TODO implement
}
From a given PropertyInfo, you can use the GetMethod and SetMethod properties to access the MethodInfo of the getter and setter, respectively.
Thus, it should be possible to compare those in a little helper method:
private static bool MethodsImplements(InterfaceMap interfaceMap,
MethodInfo interfaceMethod, MethodInfo classMethod)
{
var implIndex = Array.IndexOf(interfaceMap.InterfaceMethods, interfaceMethod);
return interfaceMethod == interfaceMap.TargetMethods[implIndex];
}
This can then be used as follows to fulfil your desired method:
var interfaceType = interfaceProperty.DeclaringType;
var interfaceMap = classProperty.DeclaringType.GetInterfaceMap(interfaceType);
var gettersMatch = classProperty.CanRead && interfaceProperty.CanRead
&& MethodImplements(interfaceMap, interfaceProperty.GetMethod, classProperty.GetMethod);
var settersMatch = classProperty.CanWrite && interfaceProperty.CanWrite
&& MethodImplements(interfaceMap, interfaceProperty.SetMethod, classProperty.SetMethod);
Then, return gettersMatch || settersMatch, as the interface property may have only a getter or only a setter.
Related
I will try to explain my best, but it is a tricky one to explain.
I am having a problem using reflection when a derived object redefines a property already in a base class.
Let's consider the following classes to start with:
// The base class
namespace MyNamesapce
{
public abstract class MyClassBase: IMyClassBase
{
[JsonConstructor]
public MyClassBase()
{
}
public string Info { get; set; }
public string Unit { get; set; }
public string Name { get; set; }
}
}
// MyClassArray is most of the time used
namespace MyNamesapce
{
public class MyClassArray<TType> : MyClassBase, IMyClassArray<TType>
{
public MyClassArray()
{
}
[JsonConstructor]
public MyClassArray(IEnumerable<TType> value, TType minValue, TType maxValue)
{
MinValue = minValue;
MaxValue = maxValue;
Value = value;
}
public IEnumerable<TType> Value { get; set; }
public TType MinValue { get; set; }
public TType MaxValue { get; set; }
}
}
// In some rare cases we need 2D arrays
namespace MyNamesapce
{
public class MyClass2DArray<TType> : MyClassArray<TType>, IMyClass2DArray<TType>
{
private int[] _arraySize { get; set; }
public MyClass2DArray()
{
}
[JsonConstructor]
public MyClass2DArray(TType[][] value, TType minValue, TType maxValue)
{
MinValue = minValue;
MaxValue = maxValue;
_arraySize = new int[2] { value.Count(), value[0].Length };
Value = value;
}
public new TType[][] Value
{
get
{
TType[][] array2D = new TType[_arraySize[0]][];
// Reconstruct the 2D array
TType[] tmpArray;
int startIdx = 0;
for (int numArrays = 0; numArrays < _arraySize[0]; numArrays++)
{
tmpArray = new TType[_arraySize[1]];
Array.Copy(base.Value.ToArray(), startIdx, tmpArray, 0, _arraySize[1]);
startIdx += _arraySize[1];
array2D[numArrays] = tmpArray;
}
return array2D;
}
set
{
// Should not be able to set _value to null
if (value == null)
return;
base.Value = value.SelectMany(v => v).ToArray();
}
}
}
}
I now need to get all the properties from all instances of MyClassArray and MyClassArray2D. You will say, there are plenty of threads discussing that very point, just use "GetType().GetProperties()" for the former and use "GetType().GetProperty(..., BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)" for the latter.
The problem is that I do not know in advance which class is being processed. In my system when deserialising a Json, instances of both MyClassArray and MyClassArray2D have to be reconstructed, which is done using the following setter:
public static void SetProperty(this Object obj, string propName, Object value)
{
PropertyInfo info = null;
object[] indexer = null;
string[] nameParts = propName.Split('.');
if (obj == null) { return; }
var props = obj.GetType().GetProperties();
for (int idx = 0; idx < nameParts.Count() - 1; idx++)
{
try
{
indexer = null;
// Try to access normal property
info = obj.GetType().GetProperty(nameParts[idx]);
if (info == null)
continue;
obj = info.GetValue(obj, indexer);
}
catch
{
info = null;
indexer = null;
}
}
if (obj != null)
{
// !!! Note that here, using declare only will only work when using derived classes
PropertyInfo propertyToSet = obj.GetType().GetProperty(nameParts.Last(), BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); // | BindingFlags.DeclaredOnly);
propertyToSet?.SetValue(obj, value);
}
else
{
throw new SystemException($"Could not find the property {propName}");
}
}
As you can see an object is passed in to SetProperty() (that can be of any type).
When it is of type MyClassArray, there are no problems, but if it is of type MyClassArray2D it does not quite work as the latter redefines "Value", which will break the logic as 2 properties called value will exist. I need a way to detect that.
The first loop seems to do the right thing. "obj = info.GetValue(obj, indexer);" will return "obj" containing all the versions of "Value". The problem is in the next part of SetProperty().
How can I detect when more than one "Value" property is in "obj"? And how to always pick the derived version of "Value"?
Also if I just use "BindingFlags.DeclaredOnly" as done here in my code snipet, properties from the base class get lost/disappear, which is undesirable.
Is there maybe a way to return in "obj" all the properties without the duplicates coming from the base class? Or some kind of property filter maybe?
How do I make this expression dynamic based on the generic type passed in the parameter?
In the simplified form:
public static class CompareService
{
public static List<T> Run<T>(List<T> database_list, string directory_path)
{
var csv_list = CompareService.MergeRecordsFromFiles<T>(directory);
return CompareService.RunComparison<T>(database_list, csv_list);
}
public static T CompareData<T>(List<T> database_list, List<T> csv_list)
{
var diff = new List<T>();
foreach (var db_item in database_list)
{
// ...
// if T is of type Deathstar compare reference_number property
// if T is of type Stormtrooper compare id property
// if T is of type Sith compare id and anger_level property
var csv_item = csv_list.FirstOrDefault(x => x.reference_number == db_item.reference_number);
// Comparison code
ComparisonResult result = compareLogic.Compare(db_item, csv_item);
// ...
}
return diff;
}
}
It is called from another generic service:
public static void Whatever<T>(List<T> list)
{
// ...
var directory_path = "C:\";
var delta = CompareService.CompareData<T>(list, directory_path);
// ...
}
The most naive implementation would be to check if your itemToFind can be cast to DeathStar, StormTrooper or Sith and if so call the instances property.
var deathStar = itemToFind as DeathStar;
if(deathStar != null)
return database_list.Where(x => ((DeathStar)x).reference_number == deathStar.reference_number).FirstOrDefault();
else
{
var sith = itemToFind as Sith;
if(sith != null)
return database_list.Where(x => ((Sith)x).anger_level == sith.anger_level).FirstOrDefault();
else
return database_list.Where(x => ((StormTrooper)x).id== ((StormTrooper)item).id).FirstOrDefault();
}
This is quite cumbersome, including many casts. In particular it completely bypasses the actual benefits of generics using any arbitrary type (that fullfills the constraints if existing). In your case you´d have a generic method that will only wortk for three decent types.
A better approach is to let all your classes implement a common interface that defines a property, for instance:
interface IObject {
int Level { get; }
}
Now all classes define that level-property:
clas DeathStar : IObject
{
public int Level { get { return this.reference_number; } }
}
clas Sith : IObject
{
public int Level { get { return this.anger_level; } }
}
clas StormTrooper: IObject
{
public int Level { get { return this.id; } }
}
Than you can use a constraint on your type T to implement that interface:
public static T CompareData<T>(List<T> list, T itemToFind) where T: IObject
Why not like this:
public static T CompareData<T>(List<T> list, Func<T, bool> predicate)
{
return database_list.FirstOrDefault(predicate);
}
And then use it like this:
var itemToFind = new ItemToFind();
var myObjectList = new List<MyObject>();
var item = CompareData<MyObject>(myObjectList, x=> x.MyObjectProperty == itemToFind.Id);
You could add a property selector:
public static class CompareService
{
public static T CompareData<T>(this List<T> list, T itemToFind, Func<T, int> propSelector)
{
int propToFind = propSelector(itemToFind); // cache
return database_list.FirstOrDefault(x => propSelector(x) == propToFind);
}
}
And call it like that:
listOfDeathstars.CompareData(deathStarToFind, ds => ds.reference_number);
listOfStormtroopers.CompareData(trooperToFind, t => t.id);
listOfSiths.CompareData(sithStarToFind, sith => new { sith.id, sith.anger_level});
Note: I added the this keyword in the signature to make it an extension (not sure if you intended that but forgot the keyword). And Where(predicate).FirstOrDefault() can be reduced to FirstOrDefault(predicate).
I started playing with roslyn few days ago and i am trying to write an extension method which tells if an IPropertySymbol has a backing field, so i thought a property has a backing field if and only if the following does not apply(as far as i am concerned):
IF its Abstract
IF its Extern
IF its ReadOnlyProperty
IF the Getter or the Setter has no Body or Empty body
so i came up with
public static bool HasBackingField(this IPropertySymbol property)
{
return !(property.IsAbstract || property.IsExtern || property.IsReadOnly);
}
My questions are
Did i miss any condition?
How do i check for the last condition? i found GetMethod and SetMethodproperties in IPropertySymbol but i don't know to check if they have a body
example to start up with
var code =
#"class XYZ
{
public int x => 4; //HasBacking field : false IsReadOnly
public int m { get { return 0;}} //HasBacking field : false IsReadOnly
public int y { get; set; } //HasBacking field : false Null body for setter or getter
public int z { get { return 0; } set { } } //HasBacking field : false Empty body for setter or getter
private int _g;
public int g //HasBacking field : true Getter and Setter has no empty Bodies
{
get { return _g; }
set { _g = value; }
}
}";
var syntaxTree = CSharpSyntaxTree.ParseText(code);
var compilation = CSharpCompilation.Create("xxx").AddSyntaxTrees(syntaxTree);
var classSymbol = compilation.GetTypeByMetadataName("XYZ");
var propSymbols = classSymbol.GetMembers().OfType<IPropertySymbol>();
var results = propSymbols.Select(ps => ps.HasBackingField()); //should be [false false false false true]
I decided to look at the syntax representation rather than the actual symbol -- the syntax is at a lower level than the symbol and contains the raw information we're interested in: looking at individual statements.
This seems to do what you're interested in:
internal static bool HasBackingField(this PropertyDeclarationSyntax property)
{
var getter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.GetAccessorDeclaration));
var setter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.SetAccessorDeclaration));
if (setter?.Body == null || getter?.Body == null)
{
return false;
}
bool setterHasBodyStatements = setter.Body.Statements.Any();
bool getterHasBodyStatements = getter.Body.Statements.Any();
return setterHasBodyStatements && getterHasBodyStatements;
}
Note that I'm not convinced this is reliable enough to conclude that there is a backing field available, but it follows the idea you had by checking if there is a body or not.
I haven't added the other checks you had in mind but these can trivially be added (either use the symbol as you already do or look through the PropertyDeclarationSyntax its modifiers/attributes).
---
Full code to test it out yourself:
public static void Execute()
{
var code =
#"class XYZ
{
public int x => 4; //HasBacking field : false IsReadOnly
public int m { get { return 0;}} //HasBacking field : false IsReadOnly
public int y { get; set; } //HasBacking field : false Null body for setter or getter
public int z { get { return 0; } set { } } //HasBacking field : false Empty body for setter or getter
private int _g;
public int g //HasBacking field : true Getter and Setter has no empty Bodies
{
get { return _g; }
set { _g = value; }
}
}";
var tree = CSharpSyntaxTree.ParseText(code);
var root = tree.GetRoot();
foreach (var prop in root.DescendantNodes().OfType<PropertyDeclarationSyntax>())
{
Console.WriteLine(prop.HasBackingField());
}
}
}
internal static class Extensions
{
internal static bool HasBackingField(this PropertyDeclarationSyntax property)
{
var getter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.GetAccessorDeclaration));
var setter = property.AccessorList?.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.SetAccessorDeclaration));
if (setter?.Body == null || getter?.Body == null)
{
return false;
}
bool setterHasBodyStatements = setter.Body.Statements.Any();
bool getterHasBodyStatements = getter.Body.Statements.Any();
return setterHasBodyStatements && getterHasBodyStatements;
}
}
Is there a clean way to query Type for properties and filter those that came from an interface?
Let's say I have a class and an interface
public interface IFoo
{
string Bar { get; set; }
}
public class Foo : IFoo
{
public string Bar { get; set; }
public string Baz { get; set; }
}
And I want to get an array of PropertyInfo's that contain only Baz property.
Edit:
This is what I have now ... I know it's not perfect, but it kinda does the job.
var allProperties = typeof(T).GetProperties();
var interfaceMethods = typeof(T).GetInterfaceMap(typeof(IFoo)).TargetMethods;
return allProperties.Where(x => !interfaceMethods.Contains(x.GetGetMethod()) || !interfaceMethods.Contains(x.GetSetMethod())).ToArray();
Looks like you want to use InterfaceMapping:
private static bool IsInterfaceImplementation(PropertyInfo p, InterfaceMapping interfaceMap)
{
var getterIndex = Array.IndexOf(interfaceMap.TargetMethods, p.GetGetMethod());
var setterIndex = Array.IndexOf(interfaceMap.TargetMethods, p.GetSetMethod());
return getterIndex != -1 || setterIndex != -1;
}
private static PropertyInfo[] GetPropertiesExcludeInterfaceImplementation(Type type, Type interfaceType)
{
var interfaceMap = type.GetInterfaceMap(interfaceType);
return type
.GetProperties()
.Where(p => !IsInterfaceImplementation(p, interfaceMap))
.ToArray();
}
You could load all interfaces that are implemented by your class and get all the properties of these interfaces. When getting the properties of your class you can check whether the property is already defined by one of the interfaces:
var interfaceProperties = typeof(Foo)
.GetInterfaces()
.SelectMany( i => i.GetProperties() )
.ToList();
var properties = typeof(Foo)
.GetProperties()
.Where(p => !interfaceProperties.Any( ip => ip.Name==p.Name && ip.PropertyType==p.PropertyType) );
Why I ran into this issue is shown with an example below with KnownValueDefinition<T> where ideally I would like to be able to output a List<KnownValueDefinition<object>> from a static class with a bunch of static readonly KnownValueDefinition<T>s
var reflectedFields =
typeof(KnownValue)
.GetFields( BindingFlags.Static | BindingFlags.Public )
.Where( p => p.FieldType.GetGenericTypeDefinition() == typeof(KnownValueDefinition<>) );
foreach( var fieldInfo in reflectedFields )
{
object value = fieldInfo.GetValue( null );
// every conversion method I've tried here fails...
}
where KnownValueDefinition<T> is basically defined as:
public class KnownValueDefinition<T>
{
// .. private members excluded for brevity
public string Key { get { return _key; } }
public T DefaultValue { get { return _defaultValue; } }
}
The short answer is NO.
Given two classes:
class BaseClass { ... }
class DerivedClass : BaseClass { ... }
and a generic class
class Widget<T> { ... }
It's instantiations
Widget<BaseClass> {...}
Widget<DerivedClass> { ... }
are pretty much treated as independent classes. You can't "upcast" like this:
Widget<DerivedClass> instance = new Widget<DerivedClass>() ;
Widget<BaseClass> upcastInstance = (Widget<DerivedClass>)instance ;
even though it seems like a perfectl sane thing to want to do.
Further, C# (and the CLR?) has no way of saying something like
Widget<?> = instance = ... ;
to indicate that all I care about is the fact that it is some instance of Widget<T>, but that I don't care about the type of T.
There's lots of questions (and answers) on this topic: just search.
You can define and implement a covariant interface:
public interface IKnownValueDefinition<out T>
{
public string Key { get; }
public T DefaultValue { get; }
}
public class KnownValueDefinition<T> : IKnownValueDefinition<T>
{
// .. private members excluded for brevity
public string Key { get { return _key; } }
public T DefaultValue { get { return _defaultValue; } }
}
Usage:
var kvdSomeClass = new KnownValueDefinition<SomeClass>();
IKnownValueDefinition<object> kvdObject = kvd; // this works
// but this will not work
var kvdInt = newKnownValueDefinition<int>();
kvdObject = kvdInt;
Covariance & Contravariance MSDN Page
Alexei's comment gave me an idea that appears to work perfectly (at least for my purposes)!:
public class KnownValueDefinition<T> :
IKnownValueDefinition
, IKnownValueDefinition<T>
{
// .. private members excluded for brevity
public string Key { get { return _key; } }
public T DefaultValue { get { return _defaultValue; } }
public KnownValueDefinition( string key, T DefaultValue )
{
//...construction logic
}
public IKnownValueDefinition<object> GetDefault()
{
return new KnownValueDefinition<object>( this._key, this._defaultValue );
}
}
public interface IKnownValueDefinition
{
IKnownValueDefinition<object> GetDefault();
}
public interface IKnownValueDefinition<out T>
{
string Key { get; }
T DefaultValue { get; }
}
and to complete this with the usage scenario:
var knownValueDefinitions = new List<IKnownValueDefinition<object>>();
var reflectedFields =
typeof(KnownValue)
.GetFields( BindingFlags.Static | BindingFlags.Public )
.Where( p => p.FieldType.GetGenericTypeDefinition() == typeof(KnownValueDefinition<>) );
foreach( var value in reflectedFields.Select( fieldInfo => fieldInfo.GetValue( null ) ) )
KnownValueDefinitions.Add( ((IKnownValueDefinition)value).GetDefault() );