cast to a variable type - c#

Is it possible to cast from a Dynamic or an Object to a variable type? The target variable type is one generic class, only the specific data type varies.
I'm looking for abstract solution, but the situation is this: I want a single Linq2SQL command for different Entities - I can GetProperty + GetValue of the EntityFramework Context, but then it must be casted to some exact types, but these come from variable input - names of DB tables.
Example of what I have:
Type NewType = typeof(System.Data.Objects.ObjectSet<>);
NewType.MakeGenericType(new Type[] {"...some type here that's variable accordint to user input - like Person, Address, Contact, ..."});
Object MyObject = Context.GetType().GetProperty("the same variable like above - Person, Address,...", BindingFlags.Public | BindingFlags.Instance).GetValue(Context, null); // this is EntityFramework Context
Example of what I need but don't know how to do it:
NewType CastedObject = (NewType) MyObject;
// or
NewType CastedObject = Convert.ChangeType(MyObject, NewType);
// or
NewType CastedObject = MyObject as NewType;
so I could do this:
(from x in CastedObject where x.ID == ID select x).FirstOrDefault();
For those, who are familiar with PHP, I'm trying to do this:
(from x in Context.$tablename where x.ID == ID select x).FirstOrDefault();

Since NewType is a runtime type, how could you have a variable of compile-time type NewType? The compiler must know the "declared" type of all variables. So what you want is not possible.
Something you can do is cast MyObject to dynamic. Then stuff like foreach (var x in CastedToDynamic) would compile (but no compile-time type checking).
You can't use LINQ on a dynamic expression, though. You will have to rewrite like:
dynamic found = null;
foreach (var x in CastedToDynamic)
{
if (x.ID == ID)
{
found = x;
break;
}
}
Note: Which overload of == to use will be decided at run-time. So even if ID is a (boxed) System.Guid, say, the == will (unbox and) call the overload of == defined inside that struct. So this works.

Something like this might get at what you are looking at (relies heavily on reflection)
List<dynamic> mylist = new List<dynamic>();
dynamic data = new ExpandoObject();
data.Foo = "foo";
data.ID = 1;
mylist.Add(data);
data = new ExpandoObject();
data.Foo = "foobar";
data.ID = 2;
mylist.Add(data);
data = new ExpandoObject();
data.Foo = "foobar2";
data.ID = 2;
mylist.Add(data);
data = new ExpandoObject();
data.Foo = "foobar2";
data.ID = 3;
mylist.Add(data);
int idiminterestedin = 2;
var dynamicselected = mylist.Select(d=>((IDictionary<string,object>)d)).Where(d=>
{
object id;
if (d.TryGetValue("ID",out id))
{
return (id is int) && (int)id == idiminterestedin;
}
return false;
});
foreach (var v in dynamicselected)
{
Console.WriteLine(v["Foo"]);
}
Console.ReadLine();
Though I'd probably skip the ExpandoObject and go straight for a dictionary:
Dictionary<string, object> data = new Dictionary<string, object>();
data["Foo"] = "foo";
data["ID"] = 1;
And then make a generic extension function(s):
static class ExptensionFunction
{
static T GetValueAs<T>(this Dictionary<string, object> obj, string key)
{
return (T)obj[key];
}
static bool TryGetValueAs<T>(this Dictionary<string, object> d, string key, out T value)
{
object id;
if (d.TryGetValue(key, out id))
{
if (id is T)
{
value = (T)id;
return true;
}
}
value = default(T);
return false;
}
static IEnumerable<Dictionary<string, object>> GetValuesWithKey<T>(this List<Dictionary<string, object>> list, string key, T value)
{
return list.Where(d =>
{
T id;
if (d.TryGetValueAs<T>(key, out id))
{
return id.Equals(value);
}
return false;
});
}
}
Inspired by this:
Creating an anonymous type dynamically?
and
Add property to anonymous type after creation

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();
}

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.

.Net dynamic list conversion

I have to do a comparison of 2 lists. The problem is that I don't know of what type the field inside the list are, they can be int, string, decimal, enums or even other objects.
I will know the type only on runtime. I was thinking of creating a list of object and cast them to object the problem is that let's say I have a List<int> and I'm trying to cast it to object it fails.
Another problem is that I know there is a list only on runtime. so on runtime I need to transform the variable of type object to a list.
How can I cast that object to List and how can I cast it to let's say list of objects?
Update:
I have and object and by reflection I'm getting the the property of it with
var oldProperty = property.GetValue(old);
var newProperty = property.GetValue(new);
Once I have the properties values and I can see it's a list I will need to compare those 2. Let's say oldProperty is of type List
I've tried to do something like:
var myOldList = (List<object>)oldProperty;
If the cast fails with
Unable to cast object of type 'System.Collections.Generic.List`1[System.Int32]' to type 'System.Collections.Generic.List`1[System.Object]'
Here you have a look of the function i;m trying to create. Please don't mind of null objects(is not in the scope)
public void SetDifference(object first, object second)
{
var properties = first.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
var oldValue = property.GetValue(first);
var newValue = property.GetValue(second);
if (Convert.GetTypeCode(newValue) != TypeCode.Object)
{
if (!oldValue.Equals(newValue))
{
result.AddDifference(new PrimitiveComparison()
{
BeforeValue = oldValue.ToString(),
AfterValue = newValue.ToString(),
PropertyName = property.Name
});
}
}
else
{
if (property.PropertyType.Name.Contains("List"))
{
// here fails with the error from above
var oldList = (List<object>)oldValue;
var newList = (List<object>)newValue;
if (oldList.Count != newList.Count)
{
result.AddDifference(new PrimitiveComparison()
{
BeforeValue = oldList.Count.ToString(),
AfterValue = newList.Count.ToString(),
PropertyName = property.Name + "Count"
});
}
// add the list differences
result.AddDifference(SetListDifference(oldList, newList);
}
else
{
var diffrence = SetDifference(oldValue, newValue);
if (!diffrence.areEqual)
{
result.AddDifference(diffrence);
}
}
}
}
}
You can just cast your two values to IList and compare them, for example like this:
static bool AreEqual(IList first, IList second) {
if (first.Count != second.Count)
return false;
for (int i = 0; i < first.Count; i++) {
if (!object.Equals(first[i], second[i]))
return false;
}
return true;
}
once you do conversion of you list than you can check both the list have same element or not by using except method of linq, to find both are equal or not
double[] numbers1 = { 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 };
double[] numbers2 = { 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 };
IEnumerable<double> onlyInFirstSet = numbers1.Except(numbers2);
if(onlyInFirstSet.Count() ==0)
Console.WriteLine("equal");
for primitive type this works fine but for user defined type you need compare implementation.
Check this blog post for comparing list of two different type : Difference between list of user defined types
If you are aware that is going to be IEnumerable type than you can try
List<object> objlst = (value as IEnumerable<object>).Cast<object>
().ToList()
you can try like this
Type t = typeof(obj);
if (t == typeof(List<int>)) {
var lst= (List<int>)obj;
} else if (t == typeof(List<string>)) {
var lst = (List<string>)obj;
} else if (t == typeof(List<decimal>)) {
var lst = (List<decimal>)obj;
}
else if (t == typeof(List<EnumName>)) {
var lst = (List<EnumName>)obj;
}

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

Using expression trees to construct an object with unknown members

I'm trying to create a generic function that will take 2 instances of a struct and create a new instance using the values of the passed-in instances. I'm mostly there but I'm having trouble figuring out how to build the expression tree to take the new values as parameters in the MemberInit (first time using expression trees).
I'm trying to avoid creating garbage (so no boxing) as much as possible.
Here's what I have so far:
private static readonly Dictionary<Type, FieldInfo[]> fieldInfoCache = new Dictionary<Type, FieldInfo[]>();
private static readonly Dictionary<FieldInfo, dynamic> compiledDelegates = new Dictionary<FieldInfo, dynamic>();
private static T Lerp<T>(T start, T end, float amount) where T : new()
{
FieldInfo[] fields;
var type = typeof(T);
if(!fieldInfoCache.TryGetValue(type, out fields))
{
fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
fieldInfoCache.Add(type, fields);
}
var binds = new List<MemberBinding>();
foreach(var fieldInfo in fields)
{
dynamic getter;
if(!compiledDelegates.TryGetValue(fieldInfo, out getter))
{
var targetExp = Expression.Parameter(type, type.Name);
var fieldExp = Expression.Field(targetExp, fieldInfo);
getter = Expression.Lambda(typeof(Func<,>).MakeGenericType(type, fieldInfo.FieldType), fieldExp, targetExp).Compile();
compiledDelegates.Add(fieldInfo, getter);
}
var startVal = getter.Invoke(start);
var endVal = getter.Invoke(end);
//This needs to be assigned to something
var newVal = fieldInfo.FieldType.IsAssignableFrom(typeof(float)) ? LerpF(startVal, endVal, amount) : Lerp(startVal, endVal, amount);
var fieldParamExp = Expression.Parameter(fieldInfo.FieldType, "newVal");
var bind = Expression.Bind(fieldInfo, fieldParamExp);
binds.Add(bind);
}
//How do I fix these two lines?
var memberInit = Expression.MemberInit(Expression.New(type), binds);
var result = Expression.Lambda<Func<T>>(memberInit).Compile().Invoke();
return result;
}
The part that I'm stumped on is how to feed the values into those last 2 lines without causing boxing
Instead of
var fieldParamExp = Expression.Parameter(fieldInfo.FieldType, "newVal");
try use
var fieldParamExp = Expression.Constant(newVal);
Update:
For efficient cache you could use something like
var startPar = Expression.Parameter(typeof (T), "start");
var endPar = Expression.Parameter(typeof (T), "end");
var amountPar = Expression.Parameter(typeof (float), "amount");
foreach (var fieldInfo in fields)
{
MethodInfo mi;
if (fieldInfo.FieldType.IsAssignableFrom(typeof (float)))
{
mi = typeof (Program).GetMethod("LerpF");
}
else
{
mi = typeof (Program).GetMethod("Lerp").MakeGenericMethod(fieldInfo.FieldType);
}
var makeMemberAccess = Expression.Call(mi, Expression.MakeMemberAccess(startPar, fieldInfo), Expression.MakeMemberAccess(endPar, fieldInfo), amountPar);
binds.Add(Expression.Bind(fieldInfo, makeMemberAccess));
}
var memberInit = Expression.MemberInit(Expression.New(type), binds);
var expression = Expression.Lambda<Func<T, T, float, T>>(memberInit, startPar, endPar, amountPar);
Func<T, T, float, T> resultFunc = expression.Compile();
// can cache resultFunc
var result = resultFunc(start, end, amount);
But I don't know how you decide to use start or end parameter, so there may be some more complex conditions in bindings.

Categories