C# - Class with List<> of other Classes - c#

I have a class, that has several elements of normal types, like int, String, etc.
It also has several elements that are various lists of other classes, that could be empty or have 1 to many items.
I have a function that I call with a generic type of the parent class, and I want to analyze data that could be in the sub elements, without knowing the types.
I am getting the parent members with the following code:
var getProperty = System.Runtime.CompilerServices.
CallSite<Func<System.Runtime.CompilerServices.CallSite,
object, object>>
.Create(Microsoft.CSharp.RuntimeBinder.
Binder.GetMember(0, property.Name, thisObject.GetType(), new[]
{
Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0, null)
}));
var thisValue = getProperty.Target(getProperty, thisObject);
I get the value into the var thisValue. At this point if I determine the underlying type of thisValue is a type of list, how can I grab the type of the list contents?
Here is the actual function....I can't seem to get it formatted nicely.
public static bool ObjectIsLike<T>(this T thisObject, T compareObject, params object[] argumentsToExclude)
{
for (int counter = 0; counter < argumentsToExclude.Length - 1; counter++)
{
argumentsToExclude[counter] = argumentsToExclude[counter].ToString().ToUpper();
}
bool objectIsLike = true;
foreach (var property in thisObject.GetType().GetProperties())
{
string fieldName = property.Name;
if (!argumentsToExclude.Contains(fieldName.ToUpper()))
{
try
{
var getProperty = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, property.Name, thisObject.GetType(), new[] { Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0, null) }));
var thisValue = getProperty.Target(getProperty, thisObject);
getProperty = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, property.Name, compareObject.GetType(), new[] { Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0, null) }));
var compareValue = getProperty.Target(getProperty, compareObject);
if (!(compareValue == null && thisValue == null))
{
if (compareValue == null || thisValue == null)
objectIsLike = false;
else
if (compareValue.GetType().FullName.Contains("List"))
{
//Ignore Lists
}
else
if (!compareValue.Equals(thisValue))
{
objectIsLike = false;
}
}
}
catch
{
objectIsLike = false;
}
}
}
return objectIsLike;
}

would GetType() work for you?
class Program
{
static void Main(string[] args)
{
MyClass1 c1 = new MyClass1();
foreach (var s in c1.pp)
{
Console.WriteLine(s.GetType());
}
Console.Read();
}
}
public class MyClass1
{
public MyClass2 p;
public List<object> pp;
public MyClass1()
{
p = new MyClass2();
pp = new List<object>();
pp.Add(new MyClass2());
pp.Add(new MyClass3());
pp.Add(new MyClass4());
}
}
public class MyClass2
{
public List<object> ppp;
public MyClass2()
{
ppp = new List<object>();
ppp.Add(new MyClass3());
ppp.Add(new MyClass4());
}
}
public class MyClass3
{
public int v;
}
public class MyClass4
{
public int v;
}

Related

Modify multiple fields of an object in an Enumerable at the same time in C#

If I have an Enumerable of objects and want to modify multiple fields of a single one that I already know the index, I currently do:
var myObject = myEnumerable[index];
myObject.one = 1;
myObject.two = 2;
Is there a way to compact that? To make it simpler?
As an example, in VB you can do:
With myEnumerable[index]
.one = 1
.two = 2
End With
PS: using doesn't work here as the object would need to implement IDisposable, we don't' always control the object. I'm looking for a generic way to do this.
Handmade way of obtaining what you wanted. You can use it on every object.
class Program
{
static void Main(string[] args)
{
var item = new Item
{
One = 0,
Two = 0
};
item.SetProperties(new string[] { "One", "Two" }, new object[] { 1, 2 });
}
}
public class Item
{
public int One { get; set; }
public int Two { get; set; }
}
public static class Extensions
{
public static void SetProperties<T>(this T obj, IEnumerable<string> propertiesNames, IEnumerable<object> propertiesValues)
{
if (propertiesNames.Count() != propertiesValues.Count())
{
throw new ArgumentNullException();
}
var properties = obj.GetType().GetProperties();
for (int i = 0; i < propertiesNames.Count(); i++)
{
var property = properties.FirstOrDefault(x => x.Name == propertiesNames.ElementAt(i));
if (property is null)
{
throw new ArgumentException();
}
property.SetValue(obj, propertiesValues.ElementAt(i));
}
}
public static void SetFields<T>(this T obj, IEnumerable<string> fieldsNames, IEnumerable<object> fieldsValues)
{
if (fieldsNames.Count() != fieldsValues.Count())
{
throw new ArgumentNullException();
}
var fields = obj.GetType().GetFields();
for (int i = 0; i < fieldsNames.Count(); i++)
{
var field = fields.FirstOrDefault(x => x.Name == fieldsNames.ElementAt(i));
if (field is null)
{
throw new ArgumentException();
}
field.SetValue(obj, fieldsValues.ElementAt(i));
}
}
}

C# Find Number of elements present in array

I want to create static class which is generic. That class should pass through each property and check if is array. If result is true, than class should check how many elements are present in class and to return that number.
What I had did till now:
public static class Helper<T> where T : class
{
private static int _counter = 0;
public static int Counter()
{
Type type = typeof(T);
foreach (var property in type.GetProperties())
{
if (property.PropertyType.IsArray)
{
}
}
return _counter;
}
}
I need help how to get number of present elements in array.
If you also want to use it on a instanced object instead of an Type you could do s.th. like this (remove the generic type of Helper and make the Counter method generic):
public static class Helper
{
// This method will only iterate the public static properties
public static int Counter<T>() where T : class => Counter(typeof(T), null);
// This method will iterate all public properties
public static int Counter<T>(T objectToCount) where T : class
{
if(objectToCount == null)
{
throw new ArgumentNullException(nameof(objectToCount));
}
return Counter(typeof(T), objectToCount);
}
public static int Counter(Type type, object instance)
{
int _counter = 0;
PropertyInfo[] properties = null;
if(instance == null)
{
properties = type.GetProperties(BindingFlags.Static | BindingFlags.Public);
}
else
{
properties = type.GetProperties();
}
foreach (var property in properties)
{
if (property.PropertyType.IsArray)
{
var array = property.GetValue(instance, null) as Array;
var length = array?.Length;
// do s.th. with your counter
}
}
return _counter;
}
}
then you could use it like:
Helper.Counter(x);
Helper.Counter<TestClass>();
Helper.Counter<TestClass>(x);
Update:
for only instanced objects it could be simplified to this:
public static int Counter(object objectToCount)
{
if(objectToCount == null)
{
throw new ArgumentNullException(nameof(objectToCount));
}
int _counter = 0;
foreach (var property in objectToCount.GetType().GetProperties())
{
if (property.PropertyType.IsArray)
{
var array = property.GetValue(objectToCount, null) as Array;
var length = array?.Length;
// do s.th. with your counter
}
}
return _counter;
}
If I get your question right, you want to get the number of array properties of a class.
in this case, you could choose two approaches.
extention method:
public static class Extensions
{
public static int NumbeofArays<TClass>(this TClass entry) where TClass : class, new()
{
Type type = typeof(TClass);
int arrays = 0;
foreach (var propertyInfo in type.GetProperties())
{
if (propertyInfo.PropertyType.IsArray)
arrays = arrays + 1;
}
return arrays;
}
}
Or a Helper Class:
public static class ClassHelper<TClass> where TClass : class, new()
{
static ClassHelper()
{
Type type = typeof(TClass);
int arrays = 0;
foreach (var propertyInfo in type.GetProperties())
{
if (propertyInfo.PropertyType.IsArray)
arrays = arrays + 1;
}
NumberofArrays = arrays;
}
public static int NumberofArrays { get; }
}
public static int Counter()
{
Type type = typeof(T);
foreach (var property in type.GetProperties())
{
Console.WriteLine(property.Name);
if (property.PropertyType.IsArray)
{
var array = property.GetValue(null, null) as Array;
Console.WriteLine(array.Length);
}
}
return _counter;
}
example: https://dotnetfiddle.net/2ICron

Get all properties and subproperties from a class

I am using reflection to get a class name, and need to get all sub properties of the class, and all the sub properties' properties.
I am running into a recursion issue where the items get added to the incorrect list.
My code is as follows:
private List<Member> GetMembers(object instance)
{
var memberList = new List<Member>();
var childMembers = new List<Member>();
foreach (var propertyInfo in instance.GetType().GetProperties())
{
var member = new Member
{
Name = propertyInfo.PropertyType.IsList() ? propertyInfo.Name + "[]" : propertyInfo.Name,
Type = SetPropertyType(propertyInfo.PropertyType),
};
if (propertyInfo.PropertyType.IsEnum)
{
member.Members = GetEnumValues(propertyInfo).ToArray();
}
if (propertyInfo.PropertyType.BaseType == typeof(ModelBase))
{
var childInstance = propertyInfo.GetValue(instance) ?? Activator.CreateInstance(propertyInfo.PropertyType);
childMembers.AddRange(GetMembers(childInstance));
member.Members = childMembers.ToArray();
}
if (propertyInfo.PropertyType.IsGenericType && (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>) ||
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
{
var itemType = propertyInfo.PropertyType.GetGenericArguments()[0];
var childInstance = Activator.CreateInstance(itemType);
childMembers.AddRange(GetMembers(childInstance));
member.Members = childMembers.Distinct().ToArray();
}
memberList.Add(member);
}
return memberList;
}
I can't know for certain since I don't have the knowledge of your code to debug and test it; however, I believe your problem may be stemming from the fact that you're re-using the childMembers list. Let me know if this is not the case.
private List<Member> GetMembers(object instance)
{
var memberList = new List<Member>();
foreach (var propertyInfo in instance.GetType().GetProperties())
{
var childMembers = new List<Member>(); // Moved to here, so it's not shared among all propertyInfo iterations.
var member = new Member
{
Name = propertyInfo.PropertyType.IsList() ? propertyInfo.Name + "[]" : propertyInfo.Name,
Type = SetPropertyType(propertyInfo.PropertyType),
};
if (propertyInfo.PropertyType.IsEnum)
{
member.Members = GetEnumValues(propertyInfo).ToArray();
}
if (propertyInfo.PropertyType.BaseType == typeof(ModelBase))
{
var childInstance = propertyInfo.GetValue(instance) ?? Activator.CreateInstance(propertyInfo.PropertyType);
childMembers.AddRange(GetMembers(childInstance));
member.Members = childMembers.ToArray();
}
if (propertyInfo.PropertyType.IsGenericType && (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>) ||
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
{
var itemType = propertyInfo.PropertyType.GetGenericArguments()[0];
var childInstance = Activator.CreateInstance(itemType);
childMembers.AddRange(GetMembers(childInstance));
member.Members = childMembers.Distinct().ToArray();
}
memberList.Add(member);
}
return memberList;
}
Wouldn't the following do?
public static IEnumerable<PropertyInfo> GetProperties(this Type type, int depth = 1)
{
IEnumerable<PropertyInfo> getProperties(Type currentType, int currentDepth)
{
if (currentDepth >= depth)
yield break;
foreach (var property in currentType.GetProperties())
{
yield return property;
foreach (var subProperty in getProperties(property.PropertyType,
currentDepth + 1))
{
yield return subProperty;
}
}
}
if (depth < 1)
throw new ArgumentOutOfRangeException(nameof(depth));
return getProperties(type, 0);
}
Given the following type:
class Foo
{
public string S { get; }
public int I { get; }
}
The output of
Console.WriteLine(string.Join(Environment.NewLine,
typeof(Foo).GetProperties(2)
.Select(p => $"{p.DeclaringType.Name}: {p.Name}")));
would be:
Foo: S
String: Chars
String: Length
Foo: I

How to set nested property value using FastMember

I get an exception when I try to set a nested member Property using FastMember. For example when having these classes
public class A
{
public B First { get; set; }
}
public class B
{
public string Second { get; set; }
}
and I want to set First.Second of an instance to "hello".
var b = new B{ Second = "some value here" };
var a = new A{ First = b };
var accessor = ObjectAccessor.Create(a);
accessor["First.Second"] = value; // this does not work and gives ArgumentOutOfRangeException
I can't split it up into ["First"]["Second"] because I don't know the depth at this point. Is there a magical access for nested properties or do I have to split the hierarchy myself?
I solved the problem recursively using an Extension Method this way:
public static class FastMemberExtensions
{
public static void AssignValueToProperty(this ObjectAccessor accessor, string propertyName, object value)
{
var index = propertyName.IndexOf('.');
if (index == -1)
{
accessor[propertyName] = value;
}
else
{
accessor = ObjectAccessor.Create(accessor[propertyName.Substring(0, index)]);
AssignValueToProperty(accessor, propertyName.Substring(index + 1), value);
}
}
}
... and this is started as follows:
ObjectAccessor.Create(a).AssignValueToProperty("First.Second", "hello")
You need to traverse the object graph using multiple ObjectAccessor instances.
public static void UseFastMember()
{
var b = new B { Second = "some value here" };
var a = new A { First = b };
var value = "hello";
var a_accessor = ObjectAccessor.Create(a);
var first = a_accessor["First"];
var b_accessor = ObjectAccessor.Create(first);
b_accessor["Second"] = value;
}
Hats off to #Beachwalker for the inspiration. But should you be using TypeAccessor as opposed to ObjectAccessor this is an extension method I've had much success with:
public static class TypeAccessorExtensions
{
public static void AssignValue<T>(this TypeAccessor accessor, T t, MemberSet members, string fieldName, object fieldValue)
{
var index = fieldName.IndexOf('.');
if (index == -1)
{
if (members.Any(m => string.Equals(m.Name, fieldName, StringComparison.OrdinalIgnoreCase)))
accessor[t, fieldName] = fieldValue;
}
else
{
string fieldNameNested = fieldName.Substring(0, index);
var member = members.FirstOrDefault(m => string.Equals(m.Name, fieldNameNested, StringComparison.OrdinalIgnoreCase));
if (member != null)
{
var nestedAccesor = TypeAccessor.Create(member.Type);
var tNested = accessor[t, fieldNameNested];
if (tNested == null)
{
tNested = Activator.CreateInstance(member.Type);
accessor[t, fieldNameNested] = tNested;
}
nestedAccesor.AssignValue(tNested, nestedAccesor.GetMembers(), fieldName.Substring(index + 1), fieldValue);
}
}
}
}

Get BaseType properties with Reflection in C#

I need to list all properties for containing class, I have a lot of them, so I don't know the type in the code, but I can get it trough prop.BastType.FullName, but I can't cast it, and I don't want to change all my classes to crate "Cast" methods everywere.
To avoid printing Property Properties such as DeclaringType,ReflectedType, etc, I'm excluding them in the code, but I don't like this way...
if (("DeclaringType,ReflectedType,MetadataToken,Module,PropertyType,Attributes,CanRead" +
",CanWrite,GetMethod,SetMethod,IsSpecialName,CustomAttributes,MemberType")
.Contains(prop.Name))
continue;
full code of Method:
private static void GetAllPropertiesFor(object oo, int level, List<KeyValuePair<string,string>> result)
{
Type entType = oo.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(entType.GetProperties());
foreach (PropertyInfo prop in props)
{
object propValue = prop.GetValue(oo, null);
if (("DeclaringType,ReflectedType,MetadataToken,Module,PropertyType,Attributes,CanRead" +
",CanWrite,GetMethod,SetMethod,IsSpecialName,CustomAttributes,MemberType")
.Contains(prop.Name))
continue;
if (propValue == null)
{
result.Add(new KeyValuePair<string, string>((new string(' ', level * 2)) + prop.Name, "Object"));
//GetAllPropertiesFor(prop, level + (1*3), result);
}
else
{
if (result == null) result = new List<KeyValuePair<string, string>>();
result.Add(new KeyValuePair<string, string>((new string(' ', level)) + prop.Name, propValue.ToString()));
}
if (entType.Namespace == "System.Data.Entity.DynamicProxies" && entType.BaseType.FullName.StartsWith("RE2012.Data.Models."))
{
GetAllPropertiesFor(prop, level + 1, result);
}
// Do something with propValue
}
}
any suggestions?
this way I don't have in results, the values of:
PropertyType : System.Int32
Attributes : None
CanRead : True
CanWrite : True
just what I need.
Disclaim i can't really work out what you want so this answer is just a shot in the dark
Based on what i think i understood you want to get the Properties from a specific Class so here is my example:
First my same Inheritance
class BaseClass
{
public int Base { get; set; }
}
class ChildClass : BaseClass
{
public double Child { get; set; }
}
class ChildChildClass : ChildClass
{
public string ChildChild { get; set; }
}
now lets find the single Properties
class Program
{
static void Main(string[] args)
{
var obj = new ChildChildClass();
var ChildChildType = obj.GetType();
var p = new Program();
// here we get the ChildClass properties
var t = p.getBaseType(ChildChildType, 1);
Console.WriteLine(t.Name);
p.getproperties(t);
// here we get the BaseClass properties
t = p.getBaseType(ChildChildType, 2);
Console.WriteLine(t.Name);
p.getproperties(t);
// here we get the Object properties
t = p.getBaseType(ChildChildType, 3);
Console.WriteLine(t.Name);
p.getproperties(t);
Console.Read();
}
internal Type getBaseType(Type t, int level)
{
Type temp ;
for (int i = 0; i < level; i++)
{
temp = t.BaseType;
if(temp == null)
throw new ArgumentOutOfRangeException("you are digging to deep");
else
t = temp;
}
return t;
}
private void getproperties(Type t)
{
PropertyInfo[] properties = t.GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance);
foreach (PropertyInfo property in properties)
{
Console.WriteLine(property.Name);
}
Console.WriteLine("");
}
}
if you want some information about BindingFlags here is a Link

Categories

Resources