Reflection get type of FieldInfo object? - c#

HI All,
I need to access the class SomeClass which is declared has a private field in the Wrapper class, using Reflection so far i have been able to get private field members . How do i cast it back to its original type so that i could access it properties and other members.
internal class Program
{
private static void Main(string[] args)
{
Wrapper wrap = new Wrapper
{
SOmeProperty = new SomeClass
{
Number = 007
}
};
Type type = wrap.GetType();
FieldInfo[] infos = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var item in infos)
{
}
}
}
internal class SomeClass
{
public int Number { get; set; }
}
internal class Wrapper
{
private SomeClass _tempSomeObj;
public SomeClass SOmeProperty
{
get
{
return _tempSomeObj;
}
set
{
_tempSomeObj = value;
}
}
}

I dont know if i understand the question correct. You want the type of the private field (backing field)??
Then you could check the FieldType property of the FieldInfo....
like this:
internal class Program
{
#region Methods
private static void Main(string[] args)
{
var wrap = new Wrapper { SOmeProperty = new SomeClass { Number = 007 } };
Type type = wrap.GetType();
FieldInfo[] fieldInfos = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var fieldInfo in fieldInfos)
{
if (fieldInfo.FieldType == typeof(SomeClass))
{
Console.WriteLine("Yap!");
}
}
}
#endregion
}
internal class SomeClass
{
#region Properties
public int Number { get; set; }
#endregion
}
internal class Wrapper
{
#region Properties
public SomeClass SOmeProperty { get; set; }
#endregion
}

Use PropertyInfo instead:
internal class Program
{
private static void Main(string[] args)
{
Wrapper wrap = new Wrapper
{
SOmeProperty = new SomeClass
{
Number = 007
}
};
Type type = wrap.GetType();
PropertyInfo info = type.GetProperty("SOmeProperty", BindingFlags.NonPublic | BindingFlags.Instance);
SomeClass value = (SomeClass)info.GetValue(wrap, null);
// use `value` variable here
}
}

I'm still a little fuzzy about what your're trying to do, but you can always GetType() on any object and get its actual run time type and query that for properties field of some other type for example
public void ListPropertiesOfType( object targetObject, Type propertyType ) {
foreach( var foundProperty in targetObject.GetType( ).GetProperties( ).Where( p => p.PropertyType == propertyType ) ) {
Console.WriteLine( "Name: {0}, Value: {1}", foundProperty.Name, foundProperty.GetValue( targetObject, null ) );
}
}
ListPropertiesOfType(new Wrapper(), typeof(SomeClass))
ListPropertiesOfType(new Wrapper(), typeof(SomeOtherClass))
If you want to pass in instances of Someclass and SomeClass that is also fine, just use GetType() on the instances to get the type that you can then use to find properties of that type as illustrated above. this works the same way regardless if you make the method generic and pass in "T" or if its non-generic and you pass in "object"

Related

C# Get constants from nested classes with reflection

I'd like to create a List from all of the constants in the nested classes.
public struct SomePair
{
public string Name, Value;
public SomePair(string name, string value)
{
Name = name;
Value = value;
}
}
private static MemberInfo[] GetClasses() => typeof(MainFoo).GetMembers(BindingFlags.Public);
private static List<Type> GetClassTypes() => GetClasses().Select(c=>c.GetType()).ToList();
public static class MainFoo
{
// The return value should contain the information about the SomeConstant's from both Errors and Foo.
public static List<LocalizationPair> Dump()
{
List<SomePair> Dump = new List<SomePair>();
var classes = GetClassTypes();
foreach (Type cls in classes)
{
var constants = cls.GetFields(BindingFlags.Public); // <<< Is always empty...
foreach (FieldInfo constant in constants)
{
Dump.Add(new SomePair(
$"{cls.Name}.{constant.Name}",
constant.GetValue(cls).ToString()
));
}
}
return Dump;
}
public static class Errors
{
public constant string SomeConstant = "a";
}
public static class Foo
{
public constant string SomeConstant = "a";
}
}
I'm able to get a list of all classes and a list of all class-types but once I try to use GetMember() on those, it returns nothing.
Use GetNestedTypes() instead with the correct BindingFlags for public constants:
var nestedTypes = typeof(MainFoo).GetNestedTypes(BindingFlags.Public);
foreach (Type type in nestedTypes)
{
FieldInfo[] constants = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
// <do stuff here>
}

SetValue Method throw Exception when using reflection

I'm trying to set value to properties in many objects.
I've a function that receive 2 parameters MyStructuredObjects and MyObject
MyStructuredObjects has a list of MyObjects.
This Function is a re-factory to remove a lot of 'if's.
I'd like to use ever the same object because the function it is used in a loop.If it is possible.
I've getting ever the exception 'Object does not match target'.
Sorry posting this, but I don't found problems like this, using List inside a Object structure.
Take a look :
public class MyStructuredObjects
{
public List<MyObject1> Object1 { get; set; }
public List<MyObject2> Object2 { get; set; }
public List<MyObject3> Object3 { get; set; }
public List<MyObject4> Object4 { get; set; }
public List<MyObject5> Object5 { get; set; }
}
private void SetValuesToObjectsToIntegrate<T>(ref MyStructuredObjects returnedObject, T obj)
{
Type t = obj.GetType();
var propertyInfo = new ObjectsToIntegrate().GetType().GetProperties();
var instance = Activator.CreateInstance(t);
foreach (var item in returnedObject.GetType().GetProperties())
{
var itemType = item.PropertyType;
if (t == itemType) // PASSING BY HERE OK , it finds the same type :P
{
item.SetValue(t, Convert.ChangeType(obj, item.PropertyType), null);
}
}
}
Update: The code should be:
item.SetValue(instance, Convert.ChangeType(obj, item.PropertyType), null);
I think I understand what you're trying to do.
It appears that you're trying to set properties like this:
var o2 = new List<MyObject2>();
var mso = new MyStructuredObjects();
SetValuesToObjectsToIntegrate(ref mso, o2);
So that mso will have its property Object2 set because the type of o2 matches the property type.
If that's the case, then you only need this code:
private void SetValuesToObjectsToIntegrate<T>(MyStructuredObjects returnedObject, T obj)
{
foreach (var propertyInfo in typeof(MyStructuredObjects).GetProperties())
{
if (typeof(T) == propertyInfo.PropertyType)
{
propertyInfo.SetValue(returnedObject, obj, null);
}
}
}
There's no need to pass MyStructuredObjects returnedObject by ref as you're not changing the instance of returnedObject.
Use this to call this code:
var o2 = new List<MyObject2>();
var mso = new MyStructuredObjects();
SetValuesToObjectsToIntegrate(mso, o2);
After this call I now get:

How to use SetValue of an Indexed Property in Reflection?

I have a C# Converter method which convers generic lists with the use of reflection.
The problem occurs when I try to call the SetValue method of the Item's property, it throws the following inner exception (ArgumentOutOfRangeException):
Index was out of range. Must be
non-negative and less than the size of the collection. Parameter name:
index.
Here is my code:
internal class Program
{
private static void Main()
{
List<ClassA> classA = new List<ClassA>();
classA.Add(new ClassA { Data = "value1" });
classA.Add(new ClassA { Data = "value2" });
List<ClassB> classB = Converter<List<ClassA>, List<ClassB>>(classA);
}
public static TOut Converter<TIn, TOut>(TIn request)
{
var response = Activator.CreateInstance<TOut>();
PropertyInfo propertyA = typeof(TIn).GetProperty("Item");
PropertyInfo propertyB = typeof(TOut).GetProperty("Item");
int count = (int)typeof(TIn).GetProperty("Count").GetValue(request);
for (int i = 0; i < count; i++)
{
var value = propertyA.GetValue(request, new object[] { i });
var b = CreateBFromA(propertyB, propertyA, value);
propertyB.SetValue(response, b, new object[] { i });
}
return response;
}
private static object CreateBFromA(PropertyInfo propertyB, PropertyInfo propertyA, object value)
{
var b = Activator.CreateInstance(propertyB.PropertyType);
object o = propertyA.PropertyType.GetProperty("Data").GetValue(value);
propertyB.PropertyType.GetProperty("Data").SetValue(b, o);
return b;
}
}
internal class ClassA
{
public string Data { get; set; }
}
internal class ClassB
{
public string Data { get; set; }
public object Other { get; set; }
}
This is a small example code of a bigger generic method (where I need to use reflection), so you can try and run it to regenerate the exception.
How to use the SetValue method to avoid this exception?
Here is my aproach to it:
public static TCollectionOut ConvertCollection<TCollectionIn, TCollectionOut, TIn, TOut>(TCollectionIn input)
where TCollectionIn : IEnumerable<TIn>
where TCollectionOut : ICollection<TOut>, new()
where TOut : new()
{
var res = new TCollectionOut();
foreach (dynamic item in input)
{
dynamic o = new TOut();
ConvertItem(item, o);
res.Add(o);
}
return res;
}
public static TCollectionOut ConvertCollectionMoreDynamic<TCollectionIn, TCollectionOut>(TCollectionIn input)
where TCollectionIn : IEnumerable
{
dynamic res = Activator.CreateInstance(typeof (TCollectionOut));
var oType = typeof (TCollectionOut).GetMethod("Add").GetParameters().Last().ParameterType;
foreach (dynamic item in input)
{
dynamic o = Activator.CreateInstance(oType);
ConvertItem(item, o);
res.Add(o);
}
return res;
}
public static void ConvertItem(ClassA input, ClassB output)
{
output.Data = input.Data;
}
If you wich to support more types just create ConvertItem method with correct overload.
This is because you are trying to pass an index to a not indexed property (Data).
If you post the ClassA code I can try yo help. Anyway you can use LINQ to perform this kind of conversions. It's faster (to write and to execute) and type safe.

PropertyInfo.SetValue() not working but no errors

I'm writing my own method to convert an object graph to a custom object since the JavaScriptSerializer fires errors on null values.
So this is what I have so far:
internal static T ParseObjectGraph<T>(Dictionary<string, object> oGraph)
{
T generic = (T)Activator.CreateInstance<T>();
Type resType = typeof(T);
foreach (PropertyInfo pi in resType.GetProperties())
{
object outObj = new object();
if (oGraph.TryGetValue(pi.Name.ToLower(), out outObj))
{
Type outType = outObj.GetType();
if (outType == pi.PropertyType)
{
pi.SetValue(generic, outObj, null);
}
}
}
return generic;
}
Now the pi.SetValue() method runs, and doesn't fire an error but when I look at the properties of generic, it's still the same as it was before hand.
The first property it goes through is a boolean so the values end up like this
generic = an object of type MyCustomType
generic.property = false
outObj = true
pi = boolean property
outType = boolean
Then after the SetValue method runs, generic.property is still set to false.
PropertyInfo.SetValue/GetValue worked with struct with accurate using
struct Z
{
public int X { get; set; }
}
Z z1 = new Z();
z1.GetType().GetProperty("X").SetValue(z1, 100, null);
Console.WriteLine(z1.X); //z1.X dont changed
object z2 = new Z();
z2.GetType().GetProperty("X").SetValue(z2, 100, null);
Console.WriteLine(((Z)z2).X); //z2.x changed to 100
Z z3 = new Z();
object _z3 = z3;
_z3.GetType().GetProperty("X").SetValue(_z3, 100, null);
z3 = (Z)_z3;
Console.WriteLine(z3.X); //z3.x changed to 100
Correct way to change struct:
box struct
change property of boxed struct
assign boxed struct to source
Found the answer. Apparently, PropertyInfo.SetValue() and PropertyInfo.GetValue() do not work for structures, only classes.
MyCustomType was unfortunately a struct, so changing this to a class made it work.
The 3rd reply in this thread states why structures do not work and classes do.
EDIT: It does work with structs, see the marked answer.
So I took your method and made a unit test of it:
class PropertySetTest
{
static readonly Type resType = typeof(Car);
internal static T ParseObjectGraph<T>(Dictionary<string, object> oGraph)
{
T generic = (T)Activator.CreateInstance<T>();
foreach (PropertyInfo pi in resType.GetProperties())
{
//No need to new() this
object outObj; // = new object();
if (oGraph.TryGetValue(pi.Name.ToLower(), out outObj))
{
Type outType = outObj.GetType();
if (outType == pi.PropertyType)
{
pi.SetValue(generic, outObj, null);
}
}
}
return generic;
}
[Test]
public void Test()
{
var typeData = new Dictionary<String, Object> {{"color", "Blue"}};
var myCar = ParseObjectGraph<Car>(typeData);
Assert.AreEqual("Blue", myCar.Color);
}
}
internal class Car
{
public String Color { get; set; }
}
This passes. Can you make it not pass in the way that you are seeing?
EDIT: With your struct, it is only marginally more complicated. See Jon Skeet's answer here regarding what's going on. As for the working code:
class PropertySetTest
{
static readonly Type resType = typeof(Car);
internal static T ParseObjectGraph<T>(Dictionary<string, object> oGraph)
{
Object generic = Activator.CreateInstance<T>();
foreach (var pi in resType.GetProperties())
{
//No need to new() this
object outObj; // = new object();
if (oGraph.TryGetValue(pi.Name.ToLower(), out outObj))
{
var outType = outObj.GetType();
if (outType == pi.PropertyType)
pi.SetValue(generic, outObj, null);
}
}
return (T)generic;
}
[Test]
public void Test()
{
var typeData = new Dictionary<String, Object> {{"color", "Blue"}};
var myCar = ParseObjectGraph<Car>(typeData);
Assert.AreEqual("Blue", myCar.Color);
}
}
internal struct Car
{
public String Color { get; set; }
}

Get FieldInfo of a field that is to be assigned

Is there any way to get FieldInfo of a field in a function that is going to assign a value to that variable?
See my example:
class SomeClass{
MyType myObject = SomeOtherClass.MyFunction();
}
class SomeOtherClass{
public static MyType MyFunction(){
//Get FieldInfo about myObject here
}
}
Background:
What I want to do is to be able to set an attribute on "myObject" which specifies that the object should be cached in "MyFunction".
Sorry Herber, I tried responding in a comment but this was to large to work as a comment:
In the case you mentioned in response to my last reply, does this work for you?
class Program
{
static void Main(string[] args)
{
SomeClass sc = new SomeClass();
}
}
class SomeClass
{
public MyType myObject;
public SomeClass()
{
SomeOtherClass.MyFunction(this);
}
}
static class SomeOtherClass
{
public static void MyFunction(SomeClass sClass)
{
sClass.myObject = new MyType() { Name = "Test1" };
FieldInfo[] fInfo = sClass.myObject.GetType().GetFields();
Console.WriteLine(fInfo[0].GetValue(sClass.myObject));
}
}
class MyType
{
public string Name;
}
This is completely impossible.
When the function is called, it has no awareness of what you're going to do with the result.
There isn't any way you can do it using the assignment operator. The MyFunction function requires a reference to the myObject object to be able to determine the field info.
Your best bet is to either check before the assignment or to pass myObject into MyFunction
Not sure if this is what your're after: But you could try using the an "out" parameter so as the method you are calling has knowledge of target of the assignment? like so:
class SomeClass
{
MyType myObject;
public SomeClass()
{
SomeOtherClass.MyFunction(out myObject);
}
}
static class SomeOtherClass
{
public static void MyFunction(out MyType mType)
{
mType = new MyType();
FieldInfo[] fInfo = mType.GetType().GetFields();
}
}
class MyType
{
string Name;
}
Hope that helps :¬)
OK one last stab before I call it a night...
class Program
{
static void Main(string[] args)
{
SomeClass sc = new SomeClass();
}
}
[AttributeUsage(AttributeTargets.Field)]
public class MyAttribute : System.Attribute
{
public readonly bool Foo;
public MyAttribute(bool foo)
{
Foo = foo;
}
}
class SomeClass
{
[MyAttribute(true)]
public MyType myObject;
[MyAttribute(true)]
public int myInt;
public bool myBool;
public SomeClass()
{
SomeOtherClass.MyFunction(this);
}
}
static class SomeOtherClass
{
public static void MyFunction(SomeClass sClass)
{
sClass.myObject = new MyType() { Name = "Test1"};
foreach(FieldInfo finfo in GetFeilds(sClass))
Console.WriteLine(finfo.GetValue(sClass));
}
public static IEnumerable<FieldInfo> GetFeilds(SomeClass sClass)
{
foreach (FieldInfo field in typeof(SomeClass).GetFields())
{
foreach (Attribute attr in field.GetCustomAttributes(true))
{
if (field.GetCustomAttributes(typeof(MyAttribute), true)!= null && ((MyAttribute)attr).Foo)
yield return field;
}
}
}
}
class MyType
{
public string Name;
}

Categories