I have to convert a generic object(s) into a NameValueCollection. I am attempting to use reflection. While I can get the parent properties, I cannot get the properties of a parent property that is an object.
Class One
public string name{get;set}
Class Two
public string desc{get;set}
public One OneName{get;set;}
public static NameValueCollection GetPropertyName(
string objType, object objectItem)
{
Type type = Type.GetType(objType);
PropertyInfo[] propertyInfos = type.GetProperties();
NameValueCollection propNames = new NameValueCollection();
foreach (PropertyInfo propertyInfo in objectItem.GetType().GetProperties())
{
if (propertyInfo.CanRead)
{
var pName = propertyInfo.Name;
var pValue = propertyInfo.GetValue(objectItem, null);
if (pValue != null)
{
propNames.Add(pName, pValue.ToString());
}
}
}
return propNames;
}
I assume there has to be somesort of recursive call but cannot figure out how to do it. Any help is appreciated.
I will assume that you want resulting NameValueCollection to contain properties from both Class One and Class Two when the input is of type Class Two.
Now that we have that established, what you can do is to examine a type of each property.
If it's one of built-in types (Type.IsPrimitive() can help you determine that), you can add the property to resulting NameValueCollection right away. Otherwise, you need to go over each property of that non-primitive type and repeat the process for it again. As you mention, here is the place for recursion.
Related
Struggled to come up with a decent way to ask/title this question, but will try and illustrate it as best I can.
I am working with a data structure something like this:
public Foo
{
public Bar Bar {get;set;}
}
public Bar
{
public SubTypeA TypeA {get;set;}
public SubTypeB TypeB {get;set;}
...
}
public SubTypeA
{
public int Status {get;set;}
...
}
Note that I am unable to change the data structure for this.
There are many different types in the Bar class, which all have different properties within them, but common to all of them is the property of Status.
What I need to do, is given an object of type Foo, is record the statuses for every item in the Bar object within it. Not every SubType is going to have a value every time though, some could be null.
I can sort of manage it by using a recursive function like below to loop through all the properties. It isn't ideal though I don't think as the loop could get quite large as there could be a lot of properties on each SubType.
private void GetProperties(Type classType, object instance)
{
foreach (PropertyInfo property in classType.GetProperties())
{
object value = property.GetValue(instance, null);
if (value != null)
{
if (property.Name == "Status")
{
Record(classType, value);
}
GetProperties(property.PropertyType, value);
}
}
}
Is this about the only approach that there is for such a problem?
EDIT: Going by the answer given by Selman22, I have come up with another issue wherein I am trying to create an anonymous object based on the status and name of object.
var z = instance.GetType()
.GetProperties()
.Select(x => new
{
status = x.GetValue(instance).GetType().GetProperty("status").GetValue(x, null),
name = x.Name
})
.ToList();
This is throwing an error of Object does not match target type. when trying to retrieve the value. Is this possible in a 1 liner?
Type class contains GetProperty(string name, BindingFlags method) that you can use to retrieve specific property. Instead of looping through every property use this method.
http://msdn.microsoft.com/en-us/library/system.type.getproperty(v=vs.110).aspx
// Get Type object of MyClass.
Type myType=typeof(MyClass);
// Get the PropertyInfo by passing the property name and specifying the BindingFlags.
PropertyInfo myPropInfo = myType.GetProperty("MyProperty", BindingFlags.Public | BindingFlags.Instance);
You can get all Status properties using LINQ instead of recursion:
var barInstance = typeof(Foo).GetProperty("Bar").GetValue(fooInstance);
var statusProperties = barInstance.GetType()
.GetProperties()
.Select(x => x.GetValue(barInstance).GetType().GetProperty("Status"));
I have a List that I am iterating through.
Inside the List<> are Argument classes which contain two properties 'PropertyName' and 'Value'
What I need to do is iterate through the collection of Arguments and assign the Value of that Argument to the Property (with the same name as current Argument) of a different class.
Example:
Argument:
PropertyName: ClientID
Value: 1234
Members Class:
ClientID = {Argument Value here}
I hope this makes sense. I have a way of doing it, hard coding the properties of my class and matching it up with the Argument list.
Something like:
foreach(var arg in List<Argument>)
{
Members.ClientID = arg.Find(x => compareName(x, "ClientID")).Value;
//where compareName just does a simple string.Compare
}
But what would the BEST way be for something like this?
EDIT: Sorry about this guys and thanks for the replies so far. Here is what I didn't mention and might make a difference.
Each argument is a different property for the same class. I am iterating through the List and each one in there will be for the same Members class I have to populate.
I wanted to mention this because im thinking in the foreach I might have to use a switch to determine what 'PropertyName' I have for that Argument. ClientID is one of them but I believe there are 14 total properties in the Members class that need populated from the Collection.
Does that change things?
Thanks again
public object this[string propertyName]
{
get
{
Type myType = typeof(UserConfiguration);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
return myPropInfo.GetValue(this, null);
}
set
{
Type myType = typeof(UserConfiguration);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
myPropInfo.SetValue(this, value, null);
}
}
Then you can get/set properties within the class using
myClassInstance["ClientId"] = myValue;
If I understand what you're asking, perhaps something like this will work for you:
var argDict = arguments.ToDictionary(x => x.PropertyName, x => x.Value);
Members.ClientID = argDict["ClientID"];
...
If you need to do some special comparison on the keys you can provide the dictionary it's own IEqualityComparer. For example, this will make sure that the keys are treated case-insensitively:
var argDict = arguments.ToDictionary(x => x.PropertyName, x => x.Value,
StringComparer.OrdinalIgnoreCase);
This will work fine as long as the arguments list contains all the values you need. If some arguments might be missing, you'd have to do something like this:
if (argDict.ContainsKey("ClientID")) {
Members.ClientID = argDict["ClientID"];
}
Or possibly something like this:
Members.ClientID = argDict.ContainsKey("ClientID") ? argDict["ClientID"] : "DefaultValue";
I think that your basic intent is to set the value of a property on a target object based on the property name. Since you did not provide the Argument class I will assume it is defined like this:
public class Argument
{
public string PropertyName{get; set;}
public object PropertyValue{get;set;}
}
Further assume you have the class Blah defined like this:
public class Blah
{
public string AString{get; set;}
public int AnInt{get; set;}
public DirectoryInfo ADirInfo{get; set;}
}
If you wish to assign to the properties of a Blah object based on the values in List<Argument> you can do so like this:
List<Argument> arguments = new List<Argument>
{
new Argument(){PropertyName = "AString", PropertyValue = "this is a string"},
new Argument(){PropertyName = "AnInt", PropertyValue = 1729},
new Argument(){PropertyName = "ADirInfo", PropertyValue = new DirectoryInfo(#"c:\logs")}
};
Blah b = new Blah();
Type blahType = b.GetType();
foreach(Argument arg in arguments)
{
PropertyInfo prop = blahType.GetProperty(arg.PropertyName);
// If prop == null then GetProperty() couldn't find a property by that name. Either it doesn't exist, it's not public, or it's defined on a parent class
if(prop != null)
{
prop.SetValue(b, arg.PropertyValue);
}
}
This depends on the objects stored in Argument.PropertyValue having the same type as the property of Blah referred to by Argument.PropertyName (or there must be an implicit type conversion available). For example, if you alter the List<Argument> as follows:
List<Argument> arguments = new List<Argument>
{
new Argument(){PropertyName = "AString", PropertyValue = "this is a string"},
new Argument(){PropertyName = "AnInt", PropertyValue = 1729},
new Argument(){PropertyName = "ADirInfo", PropertyValue = "foo"}
};
you will now get an exception when attempting to assign to Blah.ADirInfo: Object of type 'System.String' cannot be converted to type 'System.IO.DirectoryInfo'
I want to write a generic function that takes an object and a series of properties of this object. Inside the function I would like to select a new anonymous object that is simply just those properties of the passed in object.
I want to do something like this:
public class SimpleClass
{
public DateTime ADate {get; set;}
public string StringHere {get; set;}
public int ANumber {get; set;}
}
var testObj = new SimpleClass();
// set values here on testObj properties
DoStuffHere(testObj, StringHere, ANumber);
I could pass in the properties as strings and then use reflection to get the properties from the passed in object, but I wanted to know if there was some way I could pass in the properties themselves so I could have intellisense and compile time checking to prevent bad property names. I would like my getNewClass function to take any type of object, and such, be generic.
Edit: I am not returning a new anonymous type. I think my function name was making it sound that way. I am going to be selecting a new anonymous type internally from a list of that specified testObj and generating a PDF from those properties.
Defining an anonymous type is actually very complicated, and trying to do it just with the names is somewhat challenging. Essentially what you want already exists, but in regular C# - so for a single object:
var obj = new { testObj.StringHere, testObj.ANumber };
Or for multiple objects:
var projection = from obj in sequence
select new { obj.StringHere, obj.ANumber };
That's about as succinct as you'll get. You could add a generic method that took a Func<,> of some kind, but it wouldn't be any cleaner than the above.
It isn't useful to have:
var obj = SomeMagicMethod(obj, "StringHere", "ANumber");
because SomeMagicMethod could only usefully return object - our obj variable would be largely unusable.
If you don't need to return the object from the method, then you could use either of:
SomeMagicMethod<T>(T value) {
...
}
...
SomeMagicMethod(new {testObj.StringHere, testObj.ANumber });
or:
SomeMagicMethod<TFrom, TTo>(TFrom value, Func<TFrom, TTo> selector)
{
TTo actualVal = selector(value);
...
}
...
SomeMagicMethod(testObj, x => new {x.StringHere, x.ANumber });
Personally, I think the first is easier - the func in the second is overkill.
You could also just use reflection...
SomeMagicMethod(object obj, params string[] names)
{
foreach(var name in names) {
object val = obj.GetType().GetProperty(name).GetValue(obj);
// ...
}
}
//...
SomeMagicMethod(testObj, "StringHere", "ANumber");
you can pass them as lambda:
GetNewClass (testObj, ()=>StringHere, ()=> ANumber);
and have a signature for GetNewClass like
void GetNewClass (object, Expression<Func<object>> expr0, Expression<Func<object>> expr1);
You can then get the property quite easily.
You can use Linq expressions for that.
(note: it's possible you need to modify a few things in the snippet below, this is of the top of my hat):
public void getNewClass(Object testObj, params MemberExpression Fields[])
{
foreach(MemberExpression field in Fields)
{
// Get the name
var name = field.Member.Name;
// get the value
var member= Expression.Convert(field, typeof(object));
var lambda= Expression.Lambda<Func<object>>(member);
var fnc= lambda.Compile();
var value = fnc();
}
}
This snippet show how to get the name of the property and the value. It can be called like this:
getClass(someObj, obj => obj.SomeProperty, obj.SomeOtherProperty);
Please have a look at below code.
Issue is at following loc.
MyClassExample obj2 = lstObjectCollection[0] as type;
I want to type cast an object of list to its type. But type will be given at runtime.
How can we cast an object, knowing its type at runtime?
class RTTIClass
{
public void creatClass()
{
// Orignal object
MyClassExample obj1 = new MyClassExample {NUMBER1 =5 };
// Saving type of original object.
Type type = typeof(MyClassExample);
// Creating a list.
List<object> lstObjectCollection = new List<object>();
// Saving new object to list.
lstObjectCollection.Add(CreateDuplicateObject(obj1));
// Trying to cast saved object to its type.. But i want to check its RTTI with type and not by tightly coupled classname.
// How can we achive this.
MyClassExample obj2 = lstObjectCollection[0] as type;
}
public object CreateDuplicateObject(object originalObject)
{
//create new instance of the object
object newObject = Activator.CreateInstance(originalObject.GetType());
//get list of all properties
var properties = originalObject.GetType().GetProperties();
//loop through each property
foreach (var property in properties)
{
//set the value for property
property.SetValue(newObject, property.GetValue(originalObject, null), null);
}
//get list of all fields
var fields = originalObject.GetType().GetFields();
//loop through each field
foreach (var field in fields)
{
//set the value for field
field.SetValue(newObject, field.GetValue(originalObject));
}
// return the newly created object with all the properties and fields values copied from original object
return newObject;
}
}
class MyClassExample
{
public int NUMBER1 {get; set;}
public int NUMBER2{get; set;}
public int number3;
public int number4;
}
The pattern I normally use is the is operator which will tell whether your object is a particular type. This will work if you already kinda sorta know which objects you will be using
Object myObject
if(myObject is Obj1)
// do obj1 stuff
else if(myObject is Obj2)
// do stuff with obj2
I've never had it come up where i had to operate on more than a handful of different types and treat them all specially, so this is what i normally do.
You can easily get all the objects of a certain type in the list using the OfType<T> extension method:
lstObjectCollection.OfType<MyClassExample>()
If the type is only known at runtime, you can do this:
lstObjectCollection.Where(o => o.GetType() == type)
How can I read the properties of an object that contains an element of array type using reflection in c#. If I have a method called GetMyProperties and I determine that the object is a custom type then how can I read the properties of an array and the values within. IsCustomType is method to determine if the type is custom type or not.
public void GetMyProperties(object obj)
{
foreach (PropertyInfo pinfo in obj.GetType().GetProperties())
{
if (!Helper.IsCustomType(pinfo.PropertyType))
{
string s = pinfo.GetValue(obj, null).ToString();
propArray.Add(s);
}
else
{
object o = pinfo.GetValue(obj, null);
GetMyProperties(o);
}
}
}
The scenario is, I have an object of ArrayClass and ArrayClass has two properties:
-string Id
-DeptArray[] depts
DeptArray is another class with 2 properties:
-string code
-string value
So, this methods gets an object of ArrayClass. I want to read all the properties to top-to-bottom and store name/value pair in a dictionary/list item. I am able to do it for value, custom, enum type. I got stuck with array of objects. Not sure how to do it.
Try this code:
public static void GetMyProperties(object obj)
{
foreach (PropertyInfo pinfo in obj.GetType().GetProperties())
{
var getMethod = pinfo.GetGetMethod();
if (getMethod.ReturnType.IsArray)
{
var arrayObject = getMethod.Invoke(obj, null);
foreach (object element in (Array) arrayObject)
{
foreach (PropertyInfo arrayObjPinfo in element.GetType().GetProperties())
{
Console.WriteLine(arrayObjPinfo.Name + ":" + arrayObjPinfo.GetGetMethod().Invoke(element, null).ToString());
}
}
}
}
}
I've tested this code and it resolves arrays through reflection correctly.
You'll need to retrieve the property value object and then call GetType() on it. Then you can do something like this:
var type = pinfo.GetGetMethod().Invoke(obj, new object[0]).GetType();
if (type.IsArray)
{
Array a = (Array)obj;
foreach (object arrayVal in a)
{
// reflect on arrayVal now
var elementType = arrayVal.GetType();
}
}
FYI -- I pulled this code from a recursive object formatting method (I would use JSON serialization for it now).