I have a solution where i get to map out all properties and sub-properties of an object into a Dictionary.
Lets say I have something like these objects:
class MyClassA{
string info;
}
class MyClassB{
string info;
}
class MyClassC{
MyClassA a;
MyClassB b;
string something;
}
class MyClassD{
MyClassC c;
}
I created an utility to map out all the propreties so i can get something like:
MyClassD dObject = Something();
Dictionary<string, PropertyInfo> propertyMap = new Dictionary<string, PropertyInfo>();
propertyMap = buildPropertyMap(dObject );
where the string is the path and the PropertyInfo the actual property. The strings on the Map on this example would look like this (pseudo-output):
propertyMap.Keys={
c;
c.a;
c.b;
c.a.info;
c.b.info;
c.something;
}
This is a great way to tell what goes where when reading for example data from an excel file and not from xml-like things, like so:
ExcelTableC:
-----------------------
1|Ainfo|Binfo|Csomething|
-------------------------
2|value|value|valuevalue|
3|value|value|valuevalue|
-----------------------
It wall works great.
Now thing is, this is all obviously inside a couple of loops and diferent functions (because of the Excel reading process) and i need later to get the key, this is, lets say I have this 'property' and I want the path (dont ask why):
// this method does not exist (pseudo-code)
PropertyInfo.GetPath; //it would return 'c.b.info' for ex. or 'c.a.info'
So i wanted to implement a class that extended PropertyInfo to add my methods.
But doing something like:
public class PropertyField : PropertyInfo
{
PropertyField parent;
string path;
// etc...
}
returns error because PropertyInfo is an abstract class and I would need to implement all inhereted members.
I can add 'abstract' to 'PropertyField' like this:
public abstract class PropertyField : PropertyInfo {}
But then when i try to cast it like this :
private void findProperties(Type objType)
{
PropertyInfo[] properties = objType.GetProperties();
for (int i=0; i< properties.Length; i++)
{
//PropertyInfo propertyInfo = properties[i];
PropertyField property = (PropertyField) properties[i];
//do something with it
}
}
will return the following error:
System.InvalidCastException: Unable to cast object of type
'System.Reflection.RuntimePropertyInfo' to type 'App.models.PropertyField'.
So the question is, how do I add these methods? If I cant inherit what can i do?
You should do:
public class PropertyField
{
PropertyField parent;
string path;
PropertyInfo info;
// etc...
}
I see no point in inheriting PropertyInfo.
Use exstension method to extend the PropertyInfo class instead of inhriting it.
public static class Extensions
{
public static string GetPath(this PropertyInfo pi)
{
// Your implementation to get the path
}
}
The short answer is, better derive from PropertyDescriptor than from PropertyInfo. While the latter is used by the runtime environment and instantiated in RuntimePropertyInfo objects, the latter is used really to meet your purpose, to describe the property. Property descriptors have been used quite a lot in Windows.Forms, basically the whole WinForms designer is built on them and they are quite powerful.
And: you can easily inherit ``PropertyDescriptorand you even do not have to recreate a whole lot of functionality sincePropertyDescriptor` has constructors that allow you to pass in a name and a set of attributes.
Related
I have a class declared like this :
public class MyClass
{
public IMyInterface1 Prop1 { get; } = new MyImplementation1();
public IMyInterface2 Prop2 { get; } = new MyImplementation2();
public IMyInterface3 Prop3 { get; } = new MyImplementation3();
//[...]
}
I would like the list of implemented types, using reflection.
I dont have an instance of MyClass, just the type.
Ex:
static void Main(string[] args)
{
var aList = typeof(MyClass).GetProperties(); // [IMyInterface1, IMyInterface2, IMyInterface3]
var whatIWant = GetImplementedProperties(typeof(MyClass)); // [MyImplementation1, MyImplementation2, MyImplementation3]
}
IEnumerable<Type> GetImplementedProperties(Type type)
{
// How can I do that ?
}
PS: I'm not sure the title is well adapted, but I have found nothing better. I am open to suggestions.
Reflection is type metadata introspection, thus, it can't get what an actual instance of a given type may contain in their properties unless you provide an instance of the so-called type.
That's the main reason why reflection methods like PropertyInfo.GetValue have a first mandatory argument: the instance of the type where the property is declared on.
You're in the wrong direction if you want to use reflection for this. Actually you need a syntax analyzer and luckily, C# 6 comes with the new and fancy compiler formerly known as Roslyn (GitHub repository). You can also use NRefactory (GitHub repository).
Both can be used to parse actual C# code. You can parse the whole source code and then get what classes are returned in expression-bodied properties.
You can't get real types without class instance, because properties are initialized only for instances. For instance of the class, you can do something like that
List<Type> propertyTypes = new List<Type>();
PropertyInfo[] properties = typeof(MyClass).GetProperties();
foreach(PropertyInfo propertyInfo in properties)
{
propertyTypes.Add(propertyInfo.GetValue(myClassInstance));
}
With the DLR, i would like to do something like this:
class MyClass {
int MyProperty { get; set; }
}
In razor, I would do something like this. (InstanceOfMyClass is some dynamic object that looks at an instance of MyClass)
#InstanceOfMyClass.MyProperty
This would output the string representation of MyProperty.
Now if I do this.
#InstanceOfMyClass.MyMissingProperty
I would like it to output "Missing: MyMissingProperty". I would love to capture the whole expression, like so.
#InstanceOfMyClass.MyMissingProperty.MoreMissing
Could potentially output "Missing: MyMissingProperty.MoreMissing", but that might be asking a lot of the DLR.
Will the ExpandoObject allow me to do this? If not, what do I have to do to implement this?
Extend DynamicObject.TryGetMember in this way:
If the member exists, return the value. If the member doesn't exist, return a new instance of a class that will handle both the string representation of the missing property and also the chain. Something like this
public class MissingPropertyChain : DynamicObject
{
private string property;
public MissingPropertyChain(string property)
{
this.property = property;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if(binder.Name == "ToString")
result = "Missing property: " + property;
else
result = new MissingPropertyChain( property + "." + binder.Name;
return true;
}
}
I didn't try it, but I think it will give you the idea of how to solve the problem.
Hope it helps.
I am not sure about the Expando, it's rather used when you want to set the property and then get it. From what you write, however, it seems that you'd like to be able to read any value which hasn't been set before.
For this, the DynamicObject could be used. You just override the TryGetMember.
You could achieve that by creating your own version of DynamicObject then over-write the TryGetMember
http://haacked.com/archive/2009/08/26/method-missing-csharp-4.aspx
Is there a way to obtain the object behind a property by reflection?
I am trying to manage a dynamic setting of a property.
Example:
class Animal
{
public string Name {get;set;}
public string Family {get;set;}
}
class Zoo
{
public Animal Lion {get;set;}
public Animal Panda {get;set;}
}
class Test
{
public void SetLionNameWithReflection()
{
Zoo londonZoo = new Zoo();
Type zooType = typeof(Zoo);
PropertyInfo lionProperty = zooType.GetProperty("Lion");
// Now what to write here so that I can manage to set Lion's name to Kaspar?
// (to manage this by reflection Lion.Name = "Kaspar");
}
}
What lines should I add more at the commented part above?
Thanks!
I don't think you actually need to know the object behind a property. Use the SetValue method to set its value to "Kaspar":
EDIT - as per dlev's comment, this is how it should look like:
Lion kaspar = new Lion { Name="Kaspar" };
zooType.SetValue(londonZoo, kaspar, null);
A property doesn't necessarily have an object "behind" it.
It's defined by 2 functions, get and set, that can do whatever you want, and not necessarily return an object's value at all.
What you used is just a syntactic sugar to make it easier to make a property to wrap a member.
No you can't use reflection to definitively get the object behind an arbitrary property. Largely because it's not guaranteed that every property is bound to an object. It could just as easily be a calculated value.
public class Student {
public string m_firstName;
public string m_lastName;
public string FullName {
get { return String.Format("{0} {1}", m_firstName, m_lastName); }
}
}
In this case the property FullName produces a calculated value and has no single backing object.
The case you're listing though is for auto-properties. There is likely a way to dig through the fields and use a form of name matching to get the one backing a given auto-property. However such a solution would be fragile to versioning and certainly not recomended.
Can you add an overloaded constructor to your animal object, which will allow you to pass in the animal name, like this?:
londonZoo.GetProperty("Lion").SetValue(londonZoo, new Lion("Kaspar"), null);
First you need to create the lion:
var lion = Activator.CreateInstance(lionProperty.PropertyType);
Then you need to set the Lion property of the zoo:
lionProperty.SetValue(londonZoo, lion, null);
Then you can get the Name property of the lion:
PropertyInfo property = lion.GetType().GetProperty("Name",
BindingFlags.Public | BindingFlags.Instance);
Then you can set its name:
if (property != null && property.CanWrite)
{
property.SetValue(lion, "Kaspar", null);
}
In C#, I am defining a static field of a specific class. From within the class, I want to be able to display the name of the static field, pretty much like this:
public class Unit {
public string NameOfField { get { return ...; } }
}
public static Unit Hectare = new Unit();
If I now access:
Hectare.NameOfField
I want it to return:
Hectare
I know there is a static function System.Reflection.MethodBase.GetCurrentMethod(), but as far as I can tell there is no way to get the name of the instance containing this current method?
There is also the System.RuntimeFieldHandle structure, but I have not been able to identify any GetCurrentFieldHandle() method.
I am not sure if I am missing something obvious?
Any help on this is very much appreciated.
You should not count on variable names in you developments as they do not exits at runtime.
It's better to initialize Unit with a name directly:
public class Unit {
public Unit(string name)
{
NameOfField = name;
}
public string NameOfField { get; private set;} }
}
public static Unit Hectare = new Unit("Hectare");
Only way around this will be to store that information in the class:
public static Unit Hectare = new Unit("Hectare");
When your code is compiled all variable names are lost and replaced by internal references. There is no way to get that name again.
You can use Reflection to obtain class Fields and properties. Like below:
Suppose you have class with one property:
class Test
{
public static string MySupperField
{
get
{
return "Some symbols here";
}
}
}
......
You can read the property name in such way:
public string[] GetClassStaticNames(Type T)
{
string[] names;
System.Reflection.PropertyInfo[] props = T.GetProperties(); // This will return only properties not fields! For fields obtaining use T.GetFields();
names = new string[props.Count()];
for (int i = 0; i < props.Count(); i++)
{
names[i] = props[i].Name;
}
return names;
}
Hope this will help.
[EDIT]
Returning to your question - No you cant obtain name of current variable.
What you are asking about cant be done because of classes nature, they are objects in memory and reference to one object can be held in many variables, and when you are requesting value of instance field or property it will be actually performed operation with object in memory not with variable wich holds reference to that object. So obtaining name of variable wich holds reference to current instance have no sence
Thanks everyone who has taken the time to answer and discuss my question.
Just to let you know, I have implemented a solution that is sufficient for my needs. The solution is not general, and it has some pitfalls, but I'd thought I share it anyway in case it can be of help to someone else.
This is in principle what the class that is used when defining fields looks like:
public class Unit : IUnit {
public NameOfField { get; set; }
...
}
As you can see, the class implements the IUnit interface, and I have provided a public setter in the NameOfField property.
The static fields are typically defined like this within some containing class:
public static Unit Hectare = new Unit();
My solution is to set the NameOfField property through reflection before the field is used in the implementation.
I do this through a static constructor (that of course needs to be invoked before the Unit fields are accessed.
I use Linq to traverse the executing assembly for the relevant fields, and when I have detected these fields (fields which type implements the IUnit interface), I set the NameOfField property for each of them using the Any extension method:
Assembly.GetExecutingAssembly().GetTypes().
SelectMany(type => type.GetFields(BindingFlags.Public | BindingFlags.Static)).
Where(fieldInfo => fieldInfo.FieldType.GetInterfaces().Contains(typeof(IUnit))).
Any(fieldInfo =>
{
((IUnit)fieldInfo.GetValue(null)).NameOfField= fieldInfo.Name;
return false;
});
There are some shortcomings with this approach:
The static constructor has to be invoked through manual intervention before any Unit fields can be accessed
The NameOfField setter is public. In my case this is no problem, but it might be when applied in other scenarios. (I assume that the setter could be made private and invoked through further reflection, but I have not taken the time to explore that path further.)
... ?
Either way, maybe this solution can be of help to someone else than me.
Is it possible to allow methods and properties of the 'this' pointer to be resolved dynamically?
Put another way, can a class have a dynamic superclass?
Clarification
I would like to be able to subclass some class and access properties and methods that aren't defined at compile-time.
class MyClass : DynamicObject
{
public void ReceiveValue(object value) {
MyProperty = value;
}
}
DynamicObject provides a way for my code to get notified that set_MyProperty has been called with the argument value above, correct? I know this is possible if you use a syntax like:
var mc = new MyClass();
...
dynamic dmc = mc;
dmc.MyProperty = value;
But I want to be able to do this from within the methods of MyClass, almost as if I had done:
dynamic dmc = this;
dmc.MyProperty = value;
Does DynamicObject have me covered?
No, you can't have a dynamic base class. Aside from anything else, the system still needs to know how much space to allocate when you create a new instance of your class.
Could you explain what you're trying to achieve? There may well be ways in which dynamic would help without needing quite this behaviour.
EDIT: Okay, having seen your edit - I don't think you can quite do what you want, but if you just use the
dynamic dmc = this;
dmc.MyProperty = value;
or
((dynamic)this).MyProperty = value;
workaround it should be fine. To put it another way: the this reference is always statically typed, but you can have an expression with the value of this but with a dynamic type.
That shouldn't be too onerous unless you're doing a lot of dynamic work - in which case I'd recommend that you use a fully dynamic language instead. If you implement the bulk of your dynamic code in IronPython/IronRuby, you can easily integrate it with your C# code anyway.
This is the basis of polymorphism. The method/property called will be the one given lowest in the heirarchy of the objects type.
How about this:
class B
{
public void M(object o)
{
dynamic i = this;
i.P = o;
}
}
class D : B
{
public object P { get; set; }
}
class Program
{
static void Main()
{
var d = new D();
d.M(1);
}
}
I realize this is a tangent, but there are languages where every class's superclass is dynamic - i.e. where class name resolution is virtual and override-able.