creating IList<T> values at runtime from variables - c#

Im getting data from a solaceconnection which returns data as so {Account:"023": hasAccount:true} and I need to break it up and put it into two list (IList names and IList values). Names will be "Account" and "hasAccount" which I am able to do. But, Im having a problem with values. I am trying to get the type of the values ("023" and true in this example) and creating IList of type string" for "023" and IList of type bool for true. I have been trying the below but
Cache.ToList().ForEach(row => {
List<string> _namesList = new List<string>();
List<object> _valuesList = new List<object>();
FieldInfo[] fields = row.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
fields.ToList().ForEach(field => {
var fieldName = field.Name;
var fieldValue = field.GetValue(row);
_namesList.Add(fieldName);
var m_oEnum = Activator.CreateInstance(fieldValue.GetType(), new object[] { 1 }); // Length 1
//var m_oEnum = new propertyType[] { fieldValue };
_valuesList.Add(m_oEnum);
});
});
My intentions with var m_oEnum is to create a IList or array of type stirng or bool and set the fieldvalue in it. But Im not able to do it since i get the exception thrown "Constructor on type 'System.Boolean' not found." for line
var m_oEnum = Activator.CreateInstance(objectType, new object[] { 1 }); // Length 1
is it possible to create an array on the fly with a datatype and place the value in it? Thanks

Value types should be handled differently.
Cache.ToList().ForEach(row => {
List<string> _namesList = new List<string>();
List<object> _valuesList = new List<object>();
FieldInfo[] fields = row.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
fields.ToList().ForEach(field => {
var fieldName = field.Name;
var fieldValue = field.GetValue(row);
_namesList.Add(fieldName);
var objectType = fieldValue.GetType();
if (objectType.IsValueType)
{
_valuesList.Add(fieldValue);
}
else
{ // What about types without a parameterless constructor?
var m_oEnum = Activator.CreateInstance(objectType, new object[] { 1 }); // Length 1
_valuesList.Add(m_oEnum);
}
});
});

Related

Accessing elements of an Array (of any element type) from an object

I use management to access devices properties and I wrote a code below to create an array of dictionaries. my application show properties in a listview control; so I need to convert all properties value to simple string
Dictionary<string,string>[] getInfo(string k) {
// using `k` as management-key
var mos = new ManagementObjectSearcher($"select * from {k}");
var devices = new List<Dictionary<string, string>>();
var mosc = mos.Get(); // mosc is a collection of all devices with same key
foreach (var device in mosc) {
var properties = new Dictionary<string, string>();
foreach (var p in device.Properties) {
if (p.Value != null) {
if (p.IsArray) {
// I have problem in here
// my application must convert p.value to string
var collection = (IEnumerable<object>)p.Value
properties[p.Name] = string.Join(", ", collection.Select(x=>x.ToString()));
} else
properties[p.Name] = p.Value.ToString();
} else properties[p.Name] = "";
}
devices.Add(properties);
}
return devices.ToArray();
}
p.Value type is object but sometimes it contain an array like UInt[] or String[], I found part of code from stackoverflow but it didn't help me and it say:
System.InvalidCastException: 'Unable to cast object of type 'System.UInt16[]' to type 'System.Collections.Generic.IEnumerable`1[System.Object]'.'
I tried code below too, but it say same thing:
int[] array = new int[] { 0, 1, 2 }; // <- I haven't access to `array` in my main problem
object obj=array;
// I only can use `obj`
// `obj` is similar to `p.Value` here
IEnumerable<object> collection = (IEnumerable<object>)obj; // <- this line throws exception!
string output=string.join(", ",collection.Select(x=>x.ToString()));
I also tried this codes:
var collection= p.Value as IEnumerable;
// ^ found this line from stackoverflow
// says: Using the generic type 'IEnumerable<T>' requires 1 type arguments
var collection= p.Value as IEnumerable<object>
// `collection` will be null
var collection= (object[]) p.Value
// says: Unable to cast object of type 'System.Int32[]' (or some something like String[]) to type 'System.Object[]'.
IEnumerable<T> is covariant in T so this would be allowed:
IEnumerable<Giraffes> giraffes = ....
var animals = (IEnumerable<Animal>)giraffes;
So then, why does this not work as well?
var array = new[] { 1, 2, 3 };
var objects = (IEnumerable<object>)array; //will not compile
int extends object, right?
Well, the reason is that type variance in C# is only allowed between reference types; the rule is that variance must preverse identity, and there is no way to cast a value type preserving identity in C#; only reference types can and those types of conversion are called reference conversions:
var animal = (Animal)giraffe;
var o = (object)"Hello";
IFish fish = cod;
//etc.
The bits that make up the object dont change, only the type of the refernece changes, hence the name of the conversion. Note that in the very first example, animals and giraffes are the same object, object.ReferenceEquals(animals, giraffes) will return true; we've only changed the type of the variable referencing it.
In your case, to obtain an IEnumerable<object> from an IEnumerable<someValueType>, you'll have to enumerate and box each item creating a new enumerable of the desired type. In order to do so, you can use the extension method Enumerable.Cast<T>():
IEnumerable<object> objects = array.Cast<object>();
Or do the projection yourself:
IEnumerable<object> objects = array.Select(i => (object)i);
second code:
int[] array = new int[] { 0, 1, 2 };
object obj=array;
var obj_array=(Array)obj;
IEnumerable<object> collection = obj_array.Cast<object>();
string output=string.join(", ",collection.Select(x=>x.ToString()));
so main code will be:
Dictionary<string,string>[] getInfo(string k) {
// using `k` as management-key
var mos = new ManagementObjectSearcher($"select * from {k}");
var devices = new List<Dictionary<string, string>>();
var mosc = mos.Get(); // mosc is a collection of all devices with same key
foreach (var device in mosc) {
var properties = new Dictionary<string, string>();
foreach (var p in device.Properties) {
if (p.Value != null) {
if (p.IsArray) {
var array = (Array)p.Value;
var collection = array.Cast<object>();
properties[p.Name] = string.Join(", ", collection.Select(x=>x.ToString()));
} else
properties[p.Name] = p.Value.ToString();
} else properties[p.Name] = "";
}
devices.Add(properties);
}
return devices.ToArray();
}

How to set class fields using keys?

I wrote a generic method which should let us send type, an array which includes field names and an array which includes field values. I need to get class field by key from a dictionary and set value from dictionary to these fields and create new instance of this object
private static T test<T>(T obj, string[] fieldArr, string[] valueArr)
{
Type type = obj.GetType();
List<string> data = new List<string>();
var bindingFlags = BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
List<PropertyInfo> props = type.GetProperties(bindingFlags).ToList();
Dictionary<string, string> dict = new Dictionary<string, string>();
FieldInfo[] fieldInfos = type.GetFields();
for (int i = 0; i < fieldArr.Length; i++)
{
dict.Add(fieldArr[i], valueArr[i]);
}
var de = new List<PropertyInfo>();
foreach (var item in dict)
{
var fi = type.GetProperty(item.Key);
object obji = null;
fi.SetValue(obji, item.Value);
de.Add(fi);
}
return T;
}
Any suggestions?

Casting ExpandoObject to AnonymousType of T

Im trying to clone an AnonymousType and enconter some strange behavior.
could anyone tell me why and also tell me a solution.
Here is a test code.
public static T DeepClone<T>(this T objectToBeCloned) where T : class
{
// this will always return null.
return Clone(objectToBeCloned) as T;
// if i try, it will work somehow
// var o = Clone(objectToBeCloned) as dynamic;
// if I try, will get an exception cant cast
// ExpandoObject to AnonymousType even thaugh i could cast it to dynamic
// var o = (T)Clone(objectToBeCloned);
}
// the clone method
public static object Clone(this object objectToBeCloned){
object resObject;
if (primaryType.IsAnonymousType()) // dynamic types
{
var props = FastDeepClonerCachedItems.GetFastDeepClonerProperties(primaryType);
resObject = new ExpandoObject();
var d = resObject as IDictionary<string, object>;
foreach (var prop in props.Values)
{
var item = prop.GetValue(objectToBeCloned);
if (item == null)
continue;
var value = prop.IsInternalType ? item : Clone(item);
if (!d.ContainsKey(prop.Name))
d.Add(prop.Name, value);
}
return resObject;
}
dynamic test = { p1="sd" };
var v =test.DeepClone(test);
// v is always null in this case dont understand why
This isn't the cleanest code, but it clones an anonymous type:
var original = new { Name = "Albert", Age = 99 };
var constructor = original.GetType().GetConstructors().First();
var parameters = constructor.GetParameters();
var properties = original.GetType().GetProperties();
var arguments =
(
from pa in parameters
join pr in properties on pa.Name equals pr.Name
select pr.GetValue(original)
).ToArray();
var clone = constructor.Invoke(arguments);
Not much use though as anonymous types are immutable.

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 :-)

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