I'm trying to use reflection to get a property from a class. Here is some sample code of what I'm seeing:
using System.Reflection;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
PropertyInfo[] tmp2 = typeof(TestClass).GetProperties();
PropertyInfo test = typeof(TestClass).GetProperty(
"TestProp", BindingFlags.Public | BindingFlags.NonPublic);
}
}
public class TestClass
{
public Int32 TestProp
{
get;
set;
}
}
}
When I trace through this, this is what I see:
When I fetch all properties using GetProperties(), the resulting array has one entry, for property TestProp.
When I try to fetch TestProp using GetProperty(), I get null back.
I'm a little stumped; I haven't been able to find anything in the MSDN regarding GetProperty() to explain this result to me. Any help?
EDIT:
If I add BindingFlags.Instance to the GetProperties() call, no properties are found, period. This is more consistent, and leads me to believe that TestProp is not considered an instance property for some reason.
Why would that be? What do I need to do to the class for this property to be considered an instance property?
Add BindingFlags.Instance to the GetProperty call.
EDIT: In response to comment...
The following code returns the property.
Note: It's a good idea to actually make your property do something before you try to retrieve it (VS2005) :)
using System.Reflection;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
PropertyInfo[] tmp2 = typeof(TestClass).GetProperties();
PropertyInfo test = typeof(TestClass).GetProperty(
"TestProp",
BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic);
Console.WriteLine(test.Name);
}
}
public class TestClass
{
public Int32 TestProp
{
get
{
return 0;
}
set
{
}
}
}
}
Try to add the following tag:
System.Reflection.BindingFlags.Instance
EDIT: This works (at least to me)
PropertyInfo test = typeof(TestClass).GetProperty("TestProp", BindingFlags.Public | BindingFlags.Instance);
Console.WriteLine(test.Name);
You need to specify whether it is static or an instance (or both) too.
Related
I have a class something like below:
Class A : B<C>
{
public A(C entity):base(entity)
{}
}
abstract class B<T>
{
public B(T entity)
{
Entity = entity;
}
public T Entity { get; private set; }
}
Class C: D
{
public string prop2{get;set;}
}
Class D
{
public string prop1{get;set;}
}
Main()
{
A obj = new A(new C());
obj.GetType().GetProperty("prop1", BindingsFlag.Instance|BindingsFlag.FlatteredHierarchy)// is null
}
I have object of class A.
I want to get property value from this object at runtime.
I am trying with
obj.GetType().GetProprty("propertyName",
BindingsFlag.FlattenHierarchy).GetValue(obj, null);
However GetProprty() is returing null as that property is declared either in D or C class.
Can someone please suggest me how to achieve this?
Thanks in advance.
GetType().GetProperty("propertyName", BindingsFlag.FlattenHierarchy)
.GetValue(obj, null);
You are misssing binding flag that specifies wheter get instance or static property:
BindingsFlag.FlattenHierarchy | BindingsFlag.Instance
According to MSDN flag BindingsFlag.Instance or BindingsFlag.Static must be specifed explicity in order to get not null values:
You must specify either BindingFlags.Instance or BindingFlags.Static
in order to get a return.
What's more, public properties are exlcuded by default. So if you property is public you need to specify additional flag:
BindingsFlag.FlattenHierarchy | BindingsFlag.Instance | BindingsFlag.Public
Remarks:
Specify BindingFlags.Public to include public properties in the
search.
If property in base is private, FlattenHierarchy will not enumerate it:
(...) private static members in inherited classes are not included
If this is your case, I am afraid that you have to manually travel through base class and search for that property.
Make also sure, that property name is valid and exists.
EDIT:
After your edit, I see the problem. Your class A is not sub-class of D class (you want to get property from D class). That is why getting property value is not working in such way.
You need to follow the following steps:
// get entity prop value
var entityValue =
(obj.GetType()
.GetProperty("Entity",
BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public)
.GetValue(obj));
// get prop value
var prop1Value =
entityValue.GetType()
.GetProperty("prop1",
BindingFlags.FlattenHierarchy |
BindingFlags.Instance |
BindingFlags.Public)
.GetValue(entityValue);
Remember to handle null values etc.
One class has a field. Second class should be able to reference that field and to change it. Since you cannot get the address of a field in memory, I have to use reflections. But my approach only works on non-encapsulated fields. So basically:
This works:
public class Dummy
{
public int field;
public Dummy(int value)
{
this.field = value;
}
}
class Program
{
public static void Main()
{
Dummy d = new Dummy(20);
//Shows 20
Console.WriteLine(d.field.ToString());
d.GetType().GetField("field", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(d, 40);
//It should show 40 now
Console.WriteLine(d.field.ToString());
}
}
This doesn't (throws NullReferenceException):
public class Dummy
{
public int field { get; set; }
public Dummy(int value)
{
this.field = value;
}
}
class Program
{
public static void Main()
{
Dummy d = new Dummy(20);
//Shows 20
Console.WriteLine(d.field.ToString());
d.GetType().GetField("field", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(d, 40);
//It should show 40 now
Console.WriteLine(d.field.ToString());
}
}
Why? How do I fix it? Can I even access an encapsulated object like that? Thank you!
It is not a field any longer. Instead of GetField you should use GetProperty method:
d.GetType().GetProperty(...);
In both cases, you could (and should) write
d.field = 40;
When you want a field to be non-private, you should always make it a property, as in your second example. You should never have public fields. Note that if you need to access a property via reflection, you'd use GetProperty, not GetField.
Can you be more precise about the use case?
Maybe an interface that isolates the properties' accessors is better:
public interface IDummy
{
int field { get; set; }
}
You'll be able to manipulate the property without knowing anything about the rest of the object. Isn't that what you need when you want to "reference" a single field?
I have this very simple test because the full version doesn't work either;
public class dfd
{
public string g { get; set; }
}
and then;
Type myType = typeof(dfd);
FieldInfo[] b = myType.GetFields(BindingFlags.Public);
When I look at b there is no field info.
{System.Reflection.FieldInfo[0]}
Any ideas?
You have an automatic public property, which defines a private field. If you ask for the non-public fields, you'll get the backing field of that property.
BTW, you need to ask for both BindingFlags.NonPublic | BindingFlags.Instance, otherwise you won't retrieve that field.
I have a public class(TargetContainerDto) that has 2 internal properties. An enum and a type that contains a value from that enum.
I'm trying to unit test the type, but I'm having problems.
internal enum TargetContainerType
{
Endpoint,
Group,
User,
UserGroup
}
internal TargetContainerType Type { get; set; }
This is my reflection code in my test class
public void setType(TargetContainerDto t, int val)
{
BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo pi = t.GetType().GetProperty("Type", bf);
pi.SetValue(t, val, null);
}
public TargetContainerDto setTypeTo(TargetContainerDto t, int val)
{
setType(t, val);
return t;
}
TargetContainerDto has more properties than Type, but they are public so testing them is fine. The iconURL is a string defined in TargetContainerDto depending on what the type is. Here is my Testmethod:
public void DefaultSubGroupIcon()
{
var o1 = new TargetContainerDto
{
Id = 1234,
DistinguishedName = "1.1.1.1",
SubGroup = "test",
};
setType(o1, 3);
Assert.AreEqual(o1.IconUrl, "/App_Themes/Common/AppControl/Images/workstation1.png");
}
I call setTypeTo in test method when I need to set the typevalue, but I'm getting a MethodAccessException. I think it's because I don't have access to the enum. How can I access the enum through reflection?
Thanks
Mark your assembly with the InternalsVisibleTo attribute and you don't need to use reflection in your test dll.
e.g. in the AssemblyInfo.cs file in your application dll add the following line:
[assembly:InternalsVisibleTo("TestAssembly")]
see here for more details.
You asking the wrong question. A better question would be:
How do I stop testing internal state of the class?
But, if you utterly need this, there are couple of ways described in this relevant SO answer
I agree with other comments that you should try to redesign to avoid testing internal state, however I did try your code and it works fine for me (.Net 4 on VS2012).
My class library under test looks like this:
using System;
namespace ClassLibrary
{
internal enum TargetContainerType
{
Endpoint,
Group,
User,
UserGroup
}
public class TargetContainerDto
{
internal TargetContainerType Type
{
get;
set;
}
public void Print()
{
Console.WriteLine(Type);
}
}
}
And the test program (a Console app) looks like this:
using System;
using System.Reflection;
using ClassLibrary;
namespace Demo
{
internal class Program
{
private static void Main(string[] args)
{
var test = new TargetContainerDto();
setType(test, 1);
test.Print();
}
public static void setType(TargetContainerDto t, int val)
{
BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo pi = t.GetType().GetProperty("Type", bf);
pi.SetValue(t, val, null);
}
}
}
This prints out Group, as expected. If we can identify the differences between this and your actual code, we may be able to find the problem.
How to get inherited property value using reflection?
I try with BindingFlags but still trigger NullReferenceException
object val = targetObject.GetType().GetProperty("position", BindingFlags.FlattenHierarchy).GetValue(targetObject, null);
position is iherited public property and has a declared value.
EDIT:
class myParent
{
public float[] position;
public myParent()
{
this.position = new float[] { 1, 2, 3 };
}
}
class myChild : myParent
{
public myChild() : base() { }
}
myChild obj = new myChild();
PropertyInfo p = obj.GetType().GetProperty("position", BindingFlags.Instance | BindingFlags.Public);
I tried with several combinations with BindingFlags but p always is null :( ,
If you use the overload with BindingFlags you have to explicitly specify all the flags what you are interested.
Also note that: (from MSDN)
You must specify either BindingFlags.Instance or BindingFlags.Static
in order to get a return.
object val = targetObject.GetType()
.GetProperty("position",
BindingFlags.FlattenHierarchy |
BindingFlags.Instance |
BindingFlags.Public)
.GetValue(targetObject, null);
EDIT:
You have a position field not a property !.
(A good place to start learning the difference: Difference between Property and Field in C# 3.0+ especially this answer)
Change your position to a property:
public float[] position { get; set; }
Or you use the targetObject.GetType().GetField(... method to retrieve the field.
BindingFlags.FlattenHierarchy
works only for static members. Be sure to specify
BindingFlags.Instance | BindingFlags.Public
and you should get inherited properties.