C# Reflection Get List of Object - c#

I have a problem fetching object from the array object that I made. It seems it didn't fetch the object see my code below:
Product Model
public class Product
{
public string Id { get; set; }
public List<ExcelName> ShortDesc { get; set; } // I want to get the object from here
}
Short Description Model
// get this object and the properties inside it.
public class ExcelName
{
public string Name { get; set; }
public string Language { get; set; }
}
My Code
private static T SetValue<T>(Dictionary<string, object> objectValues)
{
var type = typeof(T);
var objInstance = Activator.CreateInstance(type);
if (!type.IsClass) return default;
foreach (var value in objectValues)
{
if (value.Key.Contains(":Language="))
{
var propName = value.Key.Split(':')[0];
// propName is ShortDesc object
var propInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(e => e.Name.ToLower() == propName.ToLower().Replace(" ", ""));
if (propInfo == null) continue;
if (propInfo.PropertyType.IsGenericType)
{
// I want to get the type and properties from T generic using reflection instead static
var name = typeof(ExcelName);
var excelNameObjectInstance = Activator.CreateInstance(name);
foreach (var propertyInfo in name.GetProperties())
{
propertyInfo.SetValue(excelNameObjectInstance, value.Value, null);
}
// add excelNameObjectInstance object to the list in ShortDesc
}
}
}
}
How to fetch the object from the list of ShortDesc to get the ExcelName objects.

I'm not quite sure what you're trying to do, but it seems like you want a function that instantiates a T and sets its properties according to a dictionary.
Half your code doesn't make sense to me, but my guess is correct, you shouldn't need anything more complicated than this:
private static T SetValue<T>(Dictionary<string, object> objectValues) where T : class, new()
{
var type = typeof(T);
var instance = new T();
foreach (var entry in objectValues)
{
type.GetProperty(entry.Key).SetValue(instance, entry.Value);
}
return instance;
}
If you don't expect the keys to be an exact match for property names, you can introduce a normalization function:
private static string Normalize(string input)
{
return input.ToLower().Replace(" ", "");
}
private static T SetValue<T>(Dictionary<string, object> objectValues) where T : class, new()
{
var type = typeof(T);
var instance = new T();
foreach (var entry in objectValues)
{
var prop = type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.First( x => Normalize(x.Name) == Normalize(entry.Key) );
prop.SetValue(instance, entry.Value);
}
return instance;
}

Related

How to pass Object as a generic function parameter?

I need to write a function which takes whichever Object as a parameter, iterate through its properties and write it all to the console. Here is an example:
Equipment.cs
public class Equipment
{
public string SerialNo { get; set; }
public string ModelName { get; set; }
}
People.cs
public class People
{
public string Name { get; set; }
public string Age{ get; set; }
}
Here is example of what I return to above models from API:
var equipment_res = responseObject?.items?.Select(s => new Equipment
{
SerialNo = s.serial_number,
ModelName = s.model.name,
});
var people_res = responseObject?.items?.Select(s => new Equipment
{
SerialNo = s.serial_number,
ModelName = s.model.name,
});
And now I'm struggling to write a function which can take any object and writes its properties to the console. I don't know how to properly pass objects to function in this case:
public void WriteProps(Object obj1, Object obj2)
{
foreach (Object obj1 in obj2)
{
Object obj1 = new Object();
foreach (PropertyInfo p in obj1)
{
Console.WriteLine(p.Name);
Console.WriteLine(p.GetValue(obj1, null));
}
}
}
Function call:
WriteProps(Equipment, equipment_res)
EDIT: below there's a working example but when I explicitly pass named object. It works fine but now I would like to make this function more genric:
foreach (Equipment item in equipment)
{
Equipment eq = new Equipment();
eq = item;
foreach (PropertyInfo p in eq)
{
Console.WriteLine(p.Name);
Console.WriteLine(p.GetValue(eq, null));
}
}
make your method generic and then use reflection (System.Reflection):
void WriteProps<T>(T obj)
{
foreach (var prop in typeof(T).GetProperties())
{
Console.WriteLine(prop.Name);
Console.WriteLine(prop.GetValue(obj));
}
}
Use:
WriteProps(new People
{
Name = "Test",
Age = "11"
});
WriteProps(new Equipment
{
ModelName = "test",
SerialNo = "test"
});
UPDATE:
I'd add this method to work with IEnumerable objects:
void WritePropsList<T>(IEnumerable<T> objects)
{
foreach (var obj in objects)
{
WriteProps(obj);
}
}

Reflection to get List<object> data

I'm trying to loop through a DetailClass objects inside a List using reflection just like for string fields, but I can't figure out how.
class DetailClass
{
public string FieldDetail1 { get; set; }
public string FieldDetail2 { get; set; }
public string FieldDetail3 { get; set; }
}
class SomeClass
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
public List<DetailClass> Artikli { get; set; }
}
private static PropertyInfo[] GetProperties(object obj)
{
return obj.GetType().GetProperties();
}
var myData = new SomeClass();
var prop = GetProperties(myData);
foreach (var item in prop)
{
if (item.PropertyType == typeof(string))
{
var name = item.Name,
var value = item.GetValue(myData).ToString()));
}
//how to get name and value for data inside List<DetailClass>?
}
You were trying to enumerate properties of the parent class
GetValue needs the a reference to the class you are dealing with
Code
var myData = new SomeClass();
myData.Artikli = new List<DetailClass>() { new DetailClass() { FieldDetail1 = "asd", FieldDetail2 = "sdfd", FieldDetail3 = "sdfsg" } };
foreach (var obj in myData.Artikli)
{
foreach (var item in obj.GetType().GetProperties())
{
if (item.PropertyType == typeof(string))
{
var name = item.Name;
var val = item.GetValue(obj);
Console.WriteLine(name + ", " + val);
}
}
}
Demo Here
Additional Resources
PropertyInfo.GetValue Method (Object)
Returns the property value of a specified object.
Parameters
obj
Type: System.Object
The object whose property value will be returned.
You can use your method recursively to get inside all layer of properties
You can check if
item.PropertyType.GetInterfaces().Contains(typeof(IEnumerable))
and if true cast (IEnumerable)item.GetValue(myData) and iterate on the result
recursively.
Just like TheDude answered, you can use a recursive method like so;
private void Recursion(object obj)
{
var props = GetProperties(obj);
foreach (var item in props)
{
if (item.PropertyType == typeof(string))
{
var name = item.Name;
var value = item.GetValue(obj)?.ToString();
}
else if (item.PropertyType == typeof(List<DetailClass>))
{
var test = (List<DetailClass>) item.GetValue(obj);
foreach (var t in test)
{
Recursion(t);
}
}
}
}
And do whatever you want with the name and values in the list.

.NET - Whitelisting properties to anonymous object

I want to create an anonymous object dynamically based on an existing object and a whitelist.
For example I have the following class:
class Person
{
string FirstName;
string LastName;
int Age;
}
Now I have created a function FilterObject to create a new anonymous obj based on the whitelist parameter like this:
public static class Filter
{
public static object FilterObject(Person input, string[] whitelist)
{
var obj = new {};
foreach (string propName in whitelist)
if (input.GetType().GetProperty(propName) != null)
// Pseudo-code:
obj.[propName] = input.[propName];
return obj;
}
}
// Create the object:
var newObj = Filter.FilterObject(
new Person("John", "Smith", 25),
new[] {"FirstName", "Age"});
The result should be like below. I want to use this object for my web API.
var newObj = new
{
FirstName = "John",
Age = 25
};
Is there any way to achieve this?
You can try with ExpandoObject (.net 4 or superior):
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
static class Filter
{
public static object FilterObject(Person input, string[] whitelist)
{
var o = new ExpandoObject();
var x = o as IDictionary<string, object>;
foreach (string propName in whitelist)
{
var prop = input.GetType().GetProperty(propName);
if (prop != null)
{
x[propName] = prop.GetValue(input, null);
}
}
return o;
}
}
This is only a sample based on your code, but it's a good starting point.
What about using a Dictionary?
public static object FilterObject(Person input, string[] whitelist)
{
var obj = new Dictionary<string, object>();
foreach (string propName in whitelist)
{
var prop = input.GetType().GetProperty(propName);
if(prop != null)
{
obj.Add(propName, prop.GetValue(input, null));
}
}
return obj;
}
Another thing, do you really need to return an object? Because if you are always checking for properties in the whitelist that exists in the Person type, why just not return an instance of the Person class?

get Get property from Class in Model [duplicate]

This question already has an answer here:
get Get property from ViewModel
(1 answer)
Closed 6 years ago.
I have one method for push class property into NameValuCollection
private NameValueCollection ObjectToCollection(object objects)
{
NameValueCollection parameter = new NameValueCollection();
Type type = objects.GetType();
PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance |
BindingFlags.DeclaredOnly |
BindingFlags.Public);
foreach (PropertyInfo property in properties)
{
if (property.GetValue(objects, null) == null)
{
parameter.Add(property.Name.ToString(), "");
}
else
{
if (property.GetValue(objects, null).ToString() != "removeProp")
{
parameter.Add(property.Name.ToString(), property.GetValue(objects, null).ToString());
}
}
}
return parameter;
}
In my case when I pass My Model class to this method it's for correctly, but when in my Model class I use another Model like this
public class Brand
{
public MetaTags MetaTag { get; set; } // <---- Problem is here
public string BrandName { get; set; }
}
public class MetaTags
{
public string Title { get; set; }
public string Description { get; set; }
public string Language { get; set; }
}
It's not add MetaTags Class Property to the collection and just Add MetaTag to the collection
I want this method return this OutPut
key:Title Value:value
key:Description Value:value
key:Language Value:value
key:BrandName Value:value
But this method return this
key:MetaTag Value:
key:BrandName Value:value
How I can do it ?
Here's the recursive approach to give you the desired results:
public static NameValueCollection ObjectToCollection(object objects)
{
NameValueCollection parameter = new NameValueCollection();
Type type = objects.GetType();
PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance |
BindingFlags.DeclaredOnly |
BindingFlags.Public);
foreach (var property in CollectPropertiesIncludingNestedTypes(objects, properties))
{
parameter.Add(property.Item1, property.Item2);
}
return parameter;
}
private static IEnumerable<Tuple<string, string>> CollectPropertiesIncludingNestedTypes(object source, PropertyInfo[] properties)
{
foreach (PropertyInfo property in properties)
{
if (property.GetValue(source, null) == null)
{
yield return new Tuple<string, string>(property.Name.ToString(), "");
}
else
{
var propValue = property.GetValue(source, null);
if (propValue.ToString() != "removeProp")
{
if (!(property.PropertyType.IsPrimitive || property.PropertyType == typeof(string)
|| property.PropertyType == typeof(Guid) || property.PropertyType == typeof(DateTime)))
{
foreach (var val in CollectPropertiesIncludingNestedTypes(propValue, property.PropertyType.GetProperties(BindingFlags.Instance |
BindingFlags.DeclaredOnly |
BindingFlags.Public)))
yield return val;
}
else
{
yield return new Tuple<string, string>(property.Name.ToString(), propValue.ToString());
}
}
}
}
}
To detect the custom types I used the primitive types check including the special types like string, datetime and guid. But This will give you the idea of how it can be done.

How to read value form generic method with List<T> as parameter

Maybe a silly question, I can read all the properties from list parameter but not the value in the fields of <T>.
This is the structure
public class TestRecord {
public string StringTest { get; set; }
public int IntegerTest { get; set; }
public DateTime DateTimeTest { get; set; }
}
The generic method
public void TestOfT<T>(List<T> pList) where T:class, new() {
T xt = (T)Activator.CreateInstance(typeof(T));
foreach (var tp in pList[0].GetType().GetProperties()) {
// System.Reflection.PropertyInfo pi = xt.GetType().GetProperty("StringTest");
// object s = pi.GetValue(tp, null) ; -- failed
Debug.WriteLine(tp.Name);
Debug.WriteLine(tp.PropertyType);
Debug.WriteLine(tp.GetType().Name);
}
}
Test code for generic method
public void TestTCode() {
List<TestRecord> rec = new List<TestRecord>();
rec.Add(new TestRecord() {
StringTest = "string",
IntegerTest = 1,
DateTimeTest = DateTime.Now
});
TestOfT<TestRecord>(rec);
}
Thanks for your help.
the problem is you are reading the value from the new instance (which can be written simply as var xt = new T();.
if you want to get the property of the item you need to pull the value from the instance.
void TestOfT<T>(IEnumerable<T> list) where T: class, new()
{
var properties = typeof(T).GetProperties();
foreach (var item in list)
foreach (var property in properties)
{
var name = property.Name;
var value = property.GetValue(item, null);
Debug.WriteLine("{0} is {1}", name, value);
}
}
public void TestOfT<T>(List<T> pList) where T:class, new() {
var xt = Activator.CreateInstance(typeof(T));
foreach (var tp in pList[0].GetType().GetProperties()) {
Debug.WriteLine(tp.Name);
Debug.WriteLine(tp.PropertyType);
Debug.WriteLine(tp.GetType().Name);
Debug.WriteLine(tp.GetValue(pList[0], null));
}
}

Categories