GetValue reflection on iterating through collections and get item.ToString() - c#

Inside Class TestClass:
public HashSet<string> Test = new HashSet<string>();
public List<string> Test2 = new List<string>() {"item1"};
public String Test3 = "lol";
Getting all properties with reflection:
TestClass c = new TestClass();
var properties = c.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
Now I want to iterate through the collection properties only:
var value = property.GetValue(c);
if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType) && property.PropertyType != typeof(string))
{
var valueString = string.Empty;
foreach (var item in (IEnumerable)value)
{
valueString += item.ToString() + " | ";
}
}
Works fine. Except when the collection is empty I get the collection fullname on item.ToString() instead of nothing / string.empty:
Output:
for the list I get a valueString with "item1" but for the HashSet I get a valueString of "TestClass.HashSet"
Any way to fix that?

Related

How to map dictionary with values containg tuples to class instance

I have a dictionary of type Dictionary<string, (int Id, string Code, string Name)>:
var dict = new Dictionary<string, (int Id, string Code, string Name)>
{
["subjectType"] = (1, "1Code", "1Name"),
["residentType"] = (2, "2Code", "2Name"),
["businessType"] = (3, "3Code", "3Name"),
// and so on...
};
I use tuple (int Id, string Code, string Name) here but I can replace it with a class. So, it doesn't matter tuple or class, I just need to have three properties (Id, Code, Name) for each dictionary item.
I need to project this dictionary into a class, so I map each property of output model separately like this:
public static OutputModel Map(
Dictionary<string, (int Id, string Code, string Name)> dictionary) =>
new OutputModel
{
SubjectTypeId = dictionary["subjectType"].Id,
SubjectTypeCode = dictionary["subjectType"].Code,
SubjectTypeName = dictionary["subjectType"].Name,
ResidentTypeId = dictionary["residentType"].Id,
ResidentTypeCode = dictionary["residentType"].Code,
ResidentTypeName = dictionary["residentType"].Name,
BusinessTypeId = dictionary["businessType"].Id,
BusinessTypeCode = dictionary["businessType"].Code,
BusinessTypeName = dictionary["businessType"].Name,
// and so on...
};
I wonder is there any other (more fancy) way to do the same mapping?
You could do the following.
var outPutModel = new OutputModel();
foreach (var keyValuePair in dictionary)
outPutModel.Write(keyValuePair);
public class OutputModel
{
public void Write(KeyValuePair<string, (int Id, string Code, string Name)> keyValuePair)
{
var type = typeof(OutputModel);
type.GetProperty(keyValuePair.Key + "Id", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public).SetValue(this, keyValuePair.Value.Id);
type.GetProperty(keyValuePair.Key + "Code", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public).SetValue(this, keyValuePair.Value.Code);
type.GetProperty(keyValuePair.Key + "Name", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public).SetValue(this, keyValuePair.Value.Name);
}
}
See it in action:
https://dotnetfiddle.net/jfKYsG

NHibernate AliasToBean transformer associations

I'm trying to use the following statement to get an entity with the fields I'm after:
retVal = session.CreateCriteria(typeof(MyEntity))
.CreateAlias("MyEntityProperty", "MyEntityProperty")
.Add(Restrictions.Eq("MyEntityProperty.Year", year))
.SetProjection(
Projections.Distinct(
Projections.ProjectionList()
.Add(Projections.Property("Property1"), "Property1")
.Add(Projections.Property("Property2"), "Property2")
.Add(Projections.Property("MyEntityProperty.RegisteredUser"), "MyEntityProperty.RegisteredUser")
.Add(Projections.Property("MyEntityProperty.CompanyInfo"), "MyEntityProperty.CompanyInfo")
)
)
.SetResultTransformer(Transformers.AliasToBean(typeof(MyEntity)))
.List<MyEntity>()
.Cast<BaseMyEntity>();
MyEntity is the entity I want to return, and MyEntityProperty is a property of MyEntity that is another entity (of type MyEntityProperty).
The error I get is Could not find a setter for property 'MyEntityProperty.RegisteredUser' in class 'MyEntity'
Is the AliasToBean transformer not able to handle sub entities? Or is there something more I need to do to make it work?
There is my master piece... which I'm using to transform any level of projections depth. Take it and use it like this:
.SetResultTransformer(new DeepTransformer<MyEntity>())
It could be used for any ValueType properties, many-to-one references and also for dynamic objects...
public class DeepTransformer<TEntity> : IResultTransformer
where TEntity : class
{
// rows iterator
public object TransformTuple(object[] tuple, string[] aliases)
{
var list = new List<string>(aliases);
var propertyAliases = new List<string>(list);
var complexAliases = new List<string>();
for(var i = 0; i < list.Count; i++)
{
var aliase = list[i];
// Aliase with the '.' represents complex IPersistentEntity chain
if (aliase.Contains('.'))
{
complexAliases.Add(aliase);
propertyAliases[i] = null;
}
}
// be smart use what is already available
// the standard properties string, valueTypes
var result = Transformers
.AliasToBean<TEntity>()
.TransformTuple(tuple, propertyAliases.ToArray());
TransformPersistentChain(tuple, complexAliases, result, list);
return result;
}
/// <summary>Iterates the Path Client.Address.City.Code </summary>
protected virtual void TransformPersistentChain(object[] tuple
, List<string> complexAliases, object result, List<string> list)
{
var entity = result as TEntity;
foreach (var aliase in complexAliases)
{
// the value in a tuple by index of current Aliase
var index = list.IndexOf(aliase);
var value = tuple[index];
if (value.IsNull())
{
continue;
}
// split the Path into separated parts
var parts = aliase.Split('.');
var name = parts[0];
var propertyInfo = entity.GetType()
.GetProperty(name, BindingFlags.NonPublic
| BindingFlags.Instance
| BindingFlags.Public);
object currentObject = entity;
var current = 1;
while (current < parts.Length)
{
name = parts[current];
object instance = propertyInfo.GetValue(currentObject);
if (instance.IsNull())
{
instance = Activator.CreateInstance(propertyInfo.PropertyType);
propertyInfo.SetValue(currentObject, instance);
}
propertyInfo = propertyInfo.PropertyType.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
currentObject = instance;
current++;
}
// even dynamic objects could be injected this way
var dictionary = currentObject as IDictionary;
if (dictionary.Is())
{
dictionary[name] = value;
}
else
{
propertyInfo.SetValue(currentObject, value);
}
}
}
// convert to DISTINCT list with populated Fields
public System.Collections.IList TransformList(System.Collections.IList collection)
{
var results = Transformers.AliasToBean<TEntity>().TransformList(collection);
return results;
}
}
Well wasn't I making things more complicated than necessary.
Instead of trying to set the fields on the sub entity, all I needed to do was reference the entity field itself:
.Add(Projections.Property("MyEntityProperty"), "MyEntityProperty")
and nHibernate populated it fine.
But I'm glad I asked because I got Radim's very useful code :-)

How do I find an object(s) by its hashcode?

Is there an easy way to dig in to an object and find a property or field by its hashcode? This could be a nested property or a value in a collection. The reason I ask is that I occasionally get WPF warnings that look like:
System.Windows.ResourceDictionary Warning: 9 : Resource not found;
ResourceKey='#FF000000'; ResourceKey.HashCode='51639504';
ResourceKey.Type='System.Windows.Media.SolidColorBrush'
The warning doesn't always appear and I'm having the hardest time tracking it down. I figure if I knew which object had that hashcode, I could get closer to fixing this. For instance, if I had this object:
var first = new { a = 1, b = 2, d = new { aa = 11, bb = 22 } };
and called this on it:
string str = FindHashCode(first, 22);
the result would be:
"Anon > d > bb.hashcode = 22"
or something similar. (I'm ignoring hashcode collisions for now)
Edit: Here's what I'll use based on #Alberto's answer. It searches both fields and properties whether public or non-public. It includes support for IEnumerables (Lists, Arrays, etc.) and more specifically IDictionaries. It also handles hashcode collisions. If two objects have the same hashcode, the StringBuilder will have a separate line for each object.
using System.Reflection;
static string FindHashCode(object o, int hashCode)
{
StringBuilder strb = new StringBuilder();
FindHashCode(o, hashCode, o.GetType().Name, strb);
return strb.ToString().Trim();
}
static void FindHashCode(object o, int hashCode, string path, StringBuilder strb)
{
if (o.GetHashCode() == hashCode)
{
strb.AppendLine(path + ".hashcode = " + hashCode);
}
foreach (var field in GetFieldInfo(o))
{
if (field.Item1 == null || object.ReferenceEquals(o, field.Item1))
continue;
Type type = field.Item1.GetType();
if (type.IsPrimitive)
{
if(field.Item1.GetHashCode() == hashCode)
strb.AppendLine(path + " > " + field.Item2 + ".hashcode = " + hashCode);
}
else
{
FindHashCode(field.Item1, hashCode, path + " > " + field.Item2, strb);
}
}
}
static IEnumerable<Tuple<object, string>> GetFieldInfo(object arg)
{
var ienum = arg as System.Collections.IEnumerable;
var idict = arg as System.Collections.IDictionary;
if (ienum == null && idict == null)
{
BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
Type type = arg.GetType();
var list = type.GetFields(bf).Select(s => new Tuple<object, string>(s.GetValue(arg), s.Name)).Concat(
type.GetProperties(bf).Select(s => new Tuple<object, string>(s.GetValue(arg, null), s.Name)));
foreach (var item in list)
{
yield return item;
}
}
else if (idict != null)
{
foreach (System.Collections.DictionaryEntry item in idict)
{
yield return new Tuple<object, string>(item.Key, string.Format("Dict[{0}].Key", item.Key));
yield return new Tuple<object, string>(item.Value, string.Format("Dict[{0}].Value", item.Key));
}
}
//note that dictionaries implement IEnumerable
else if (ienum != null && !(ienum is string))
{
int count = 0;
foreach (var item in ienum)
{
yield return new Tuple<object, string>(item, string.Format("this[{0}]", count));
count++;
}
}
}
Here an implementation that search recursively in an object graph for a property with a specific hashcode:
static string FindHashCode(object o, int hashCode)
{
return FindHashCodeImpl(o,hashCode, o.GetType().Name);
}
static string FindHashCodeImpl(object o, int hashCode, string partialPath)
{
var type = o.GetType();
var properties = type.GetProperties();
foreach (var property in properties)
{
var propValue = property.GetValue(o);
if (propValue.GetHashCode() == hashCode)
{
return partialPath + " > " + property.Name + ".hashcode = " + hashCode;
}
var path = FindHashCodeImpl(propValue, hashCode, partialPath + " > " + property.Name);
if (path != null)
{
return path;
}
}
return null;
}
Use it like:
var o = new { a = 1, b = 2, d = new { aa = 11, bb = 22 } };
var s = FindHashCode(o, 22); //Output "<>f__AnonymousType1`3 > d > bb.hashcode = 22"
You should extend it to search inside fields as well.
P.S I didn't test it for every scenario, but it should work...
There's no automatic way to search a graph of objects for a member whose hashcode matches a certain value. But if you know the structure (like a List) then you can go along and GetHashCode() for each one and return the matches (of which there could be many). I think you must have some concept of the data you're working with, some container such as a list or tree, right?
The Visual Studio debugger also lets you assign Object IDs to items in the watches so that you can know that two references are to the same item, in case that helps.
I think there are faster ways to find your bug.
Trace WPF System.Windows.ResourceDictionary warning Resource not found

List all SystemColors

In Windows.Forms, I need to create a program which accepts any color and tries to find the corresponding system colors to it.
I was not able to figure out how to loop through all Colors of the System.Drawing.SystemColors class - it's a class, not an enum or a List.
How can I do this (some kind of reflection?)?
How about
public static Dictionary<string,object> GetStaticPropertyBag(Type t)
{
const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
var map = new Dictionary<string, object>();
foreach (var prop in t.GetProperties(flags))
{
map[prop.Name] = prop.GetValue(null, null);
}
return map;
}
or
foreach (System.Reflection.PropertyInfo prop in typeof(SystemColors).GetProperties())
{
if (prop.PropertyType.FullName == "System.Drawing.Color")
ColorComboBox.Items.Add(prop.Name);
}
And I cooked something up.
var typeToCheckTo = typeof(System.Drawing.Color);
var type = typeof(System.Drawing.SystemColors);
var fields = type.GetProperties(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).Where(p => p.PropertyType.Equals(typeToCheckTo));
foreach (var field in fields)
{
Console.WriteLine(field.Name + field.GetValue(null, null));
}

Get all data from the object into one two-dimentional array

I need to dump all data from the object into two-dimetional array
this is the declaration:
GetItemCall oGetItemCall = new GetItemCall(oContext);
then, I can use oGetItemCall.Item.ConditionID or oGetItemCall.Item.ListingDetails.EndTime etc.
But the oGetItemCall object has lots of variables and I want to add them into one easy to read 2-dimensional array.
Is there any way of doing this ?
Array is required?
Why don't use a more flexible structure, like list. So try to convert object to list. A list can be easily accessed through indexes: in this case through the object's properties names.
Reflection can solve the problem.
Have a look here.
It's not clear why you would want to do that, however either one of those should do.
string[,] some = new string[100,2];
Hashtable table = new Hashtable();
// array
some[0,0] = "Key";
some[0,1] = "value";
// hashtable
table["key"] = "value";
So you want to look at the item and all of it's properties and values? Use reflection.
It is not perfect and by no means complete - but will give you a good starting point if this is what you want. Easily extendible to add type names, etc.
public static List<string> ReflectObject(object o)
{
var items = new List<string>();
if (o == null)
{
items.Add("NULL"); // remove if you're not interested in NULLs.
return items;
}
Type type = o.GetType();
if (type.IsPrimitive || o is string)
{
items.Add(o.ToString());
return items;
}
items.Add(string.Format("{0}{1}{0}", " ----- ", type.Name));
if (o is IEnumerable)
{
IEnumerable collection = (IEnumerable)o;
var enumerator = collection.GetEnumerator();
while (enumerator.MoveNext())
{
foreach (var innerItem in ReflectObject(enumerator.Current))
{
items.Add(innerItem);
}
}
}
else
{
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties)
{
object value = property.GetValue(o, null);
foreach (var innerItem in ReflectObject(value))
{
items.Add(string.Format("{0}: {1}", property.Name, innerItem));
}
}
}
return items;
}
It can be used like this:
Test t = new Test();
t.MyProperty1 = 123;
t.MyProperty2 = "hello";
t.MyProperty3 = new List<string>() { "one", "two" };
t.MyTestProperty = new Test();
t.MyTestProperty.MyProperty1 = 987;
t.MyTestProperty.MyTestProperty = new Test();
t.MyTestProperty.MyTestProperty.MyProperty2 = "goodbye";
var items = MyReflector.ReflectObject(t);
foreach (var item in items)
{
Console.WriteLine(item);
}
This would result in:
----- Test -----
MyProperty1: 123
MyProperty2: hello
MyProperty3: ----- List`1 -----
MyProperty3: one
MyProperty3: two
MyTestProperty: ----- Test -----
MyTestProperty: MyProperty1: 987
MyTestProperty: MyProperty2: NULL
MyTestProperty: MyProperty3: NULL
MyTestProperty: MyTestProperty: ----- Test -----
MyTestProperty: MyTestProperty: MyProperty1: 0
MyTestProperty: MyTestProperty: MyProperty2: goodbye
MyTestProperty: MyTestProperty: MyProperty3: NULL
MyTestProperty: MyTestProperty: MyTestProperty: NULL

Categories