Dynamic casting to a generic type - c#

I'm trying to get to the Cases.Values property of System.Activities.Statements.Switch object. The problem is that I cannot cast Activity object at runtime to Switch<> type (which derives from it).
var switchType = activity.GetType();
bool isSwitch = (switchType.IsGenericType && switchType.GetGenericTypeDefinition() == typeof(Switch<>));
if (isSwitch)
{
Type[] genericArgumentTypes = switchType.GetGenericArguments();
if (genericArgumentTypes.Length > 0)
{
var switchStatement = (Switch<genericArgumentTypes[0]>) activity; //that's incorrect
foreach (var aCase in switchStatement.Cases.Values)
{
ProcessActivity(aCase, dataSets, context);
}
}
}
Also,
dynamic switchStatement = activity;
foreach (var aCase in switchStatement.Cases.Values)
{
ProcessActivity(aCase, dataSets, context);
}
throws an error, that the property is not there, while debugger is showing it's not true. The T is irrelevant for me - I need only the Cases collection.
EDIT
Actually, I've found even cleaner solution, than the one I set as an answer.
dynamic switchStatement = activity;
var cases = switchStatement.Cases as IEnumerable;
if (cases != null)
{
foreach (dynamic aCase in cases)
{
ProcessActivity(aCase.Value);
}
}

You can't.
But instead of your loop, put:
var process = typeof(CurrentHelperClass).GetMethod("ProcessSwitch`1").MakeGenericMethod(typeof(genericArgumentTypes[0]));
process.Invoke(null,new object[]{activity});
and define a new method in the same class:
static void ProcessSwitch<T>(Switch<T> switchStatement)
{
foreach (var aCase in switchStatement.Cases.Values)
{
ProcessActivity(aCase, dataSets, context);
}
}

var switchType = activity.GetType();
var prop = switchType.GetProperty("Cases", System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance); //move it outside of the method and use the same property for every time you call the method since it's performance expansive.
bool isSwitch = (switchType.IsGenericType && switchType.GetGenericTypeDefinition() == typeof(Switch<>));
if (isSwitch)
{
IEnumerable dictionary = prop.GetValue(activity,null) as IDictionary;
foreach (var item in dictionary.Values)
{
ProcessActivity(item, dataSets, context);
}
}

Related

Having trouble with an ICollection/IEnumerable operation - won't remove an occurrence

I'm using a FastObjectListView to enter S/Ns of units to a Disposition (sold, RMA, etc) and I enter a constant for the first S/N - "(Enter Serial)"
I'm using this same model in another section of code (RMA) but I'm missing something when trying to do the same operation for Disposition.
public UnitHistory RemoveUnit(Unit unit)
{
if (unit == null)
{
return null;
}
IEnumerable<UnitHistory> seq = AssociatedUnits.Where(p => p.Unit.Equals(unit));
var unitHistories = seq.ToList();
if (unitHistories.Any())
{
List<UnitHistory> collection = new List<UnitHistory>();
collection.AddRange(AssociatedUnits);
collection.Remove(unitHistories[0]);
AssociatedUnits.Clear();
foreach (UnitHistory history in collection)
{
AssociatedUnits.Add(history);
}
unitHistories[0].Disposition = null;
DisassociatedUnits.Add(unitHistories[0]);
unitHistories[0].Unit.UnitHistory.Remove(unitHistories[0]);
return unitHistories[0];
}
return null;
}
The code won't remove unitHistories[0] from collection.
This model does work in the following code:
public RmaRepairNotes RemoveUnit(Unit unit)
{
if (unit == null)
{
return null;
}
IEnumerable<RmaRepairNotes> seq = AssociatedUnits.Where(p => p.Unit.Equals(unit));
var unitRmaHistories = seq.ToList();
if (unitRmaHistories.Any())
{
List<RmaRepairNotes> collection = new List<RmaRepairNotes>();
collection.AddRange(AssociatedUnits);
collection.Remove(unitRmaHistories[0]);
AssociatedUnits.Clear();
foreach (RmaRepairNotes note in collection)
{
AssociatedUnits.Add(note);
}
unitRmaHistories[0].Rma = null;
DisassociatedUnits.Add(unitRmaHistories[0]);
unitRmaHistories[0].Unit.RmaRepairNotes.Remove(unitRmaHistories[0]);
return unitRmaHistories[0];
}
return null;
}
AssociatedUnits is an ICollection in both classes.
EDIT - SOLUTION: I found a logic error in the Equals code of the UnitHistory class. Now it functions perfectly.
The UnitHistory Class had a logic error in the Equals function. Now that objects could be identified as being equal, the code functions perfectly.

.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;
}

c# Reflection Generic List Count

Is there a cleaner way to get a list count using reflection then this?
Boolean include = false;
foreach (PropertyInfo item in props)
{
var pt = item.PropertyType;
String listType = pt.GetGenericArguments()[0].Name;
// Is there a better solution than this?
switch (listType)
{
case "jsonResult":
var list = v as List<jsonResult>;
include = list.count > 0;
break;
}
}
)
I've tried a variety of ideas from Googling but haven't had any luck.
I didn't completely understand what is the "v" variable, but if it is an object and when it's a collection you want to get its count, you can do that this way:
var count = GetCount(v);
if (!count.HasValue)
continue; // Or any other code here
include = count.Value > 0;
The "GetCount" method:
private static int? GetCount(object #object)
{
var collection = #object as System.Collections.ICollection;
if (collection == null)
return null;
return collection.Count;
}

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

Saving a class to a delim file using reflection

I want to write the property names and matching data to a delimited file, I've copied some code from the c# objectdumper help file and it all seems to work OK but I dont understand reflection enough to be confident to use it. What I'm worried about is an incorrect value being placed in the incorrect column, is it possible for this to happen e.g.
Field1,Field2
Val1,Val2
Val1,Val2
Val2,Val1 << Could this ever happen ?
Also what does this piece of code mean?
f != null ? f.GetValue(this) : p.GetValue(this, null)
Code below:
public string returnRec(bool header, string delim)
{
string returnString = "";
bool propWritten = false;
MemberInfo[] members = this.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
foreach (MemberInfo m in members)
{
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null)
{
if (propWritten)
{
returnString += delim;
}
else
{
propWritten = true;
}
if (header)
returnString += m.Name;
else
{
Type t = f != null ? f.FieldType : p.PropertyType;
if (t.IsValueType || t == typeof(string))
{
returnString += f != null ? f.GetValue(this) : p.GetValue(this, null);
}
}
}
}
return returnString;
}
Type t = f != null ? f.FieldType : p.PropertyType;
this is an inline if, asking is f != null then f.FieldType else p.PropertyType
can be written as
Type t;
if (f != null)
t = f.FieldType;
else
t = p.PropertyType;
#astander and #Frederik have essentially answered the questions and concerns that you specifically voiced, but I'd like to suggest doing things in a slightly more efficient manner. Depending on the number of object instances that you wish to write to your file, the method that you've presented may end up being quite inefficient. That's because you're gleaning type and value information via reflection on every iteration, which is unnecessary.
What you're looking for is something that looks up type information once, and then only uses reflection to get the value of properties and fields, e.g. (.NET 3.5),
public static IEnumerable<string> ReturnRecs(IEnumerable items, bool returnHeader, string delimiter)
{
bool haveFoundMembers = false;
bool haveOutputHeader = false;
PropertyInfo[] properties = null;
FieldInfo[] fields = null;
foreach (var item in items)
{
if (!haveFoundMembers)
{
Type type = item.GetType();
properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(pi => pi.PropertyType.IsValueType || pi.PropertyType == typeof (string)).ToArray();
fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(fi => fi.FieldType.IsValueType || fi.FieldType == typeof(string)).ToArray();
haveFoundMembers = true;
}
if (!haveOutputHeader)
{
yield return String.Join(delimiter, properties.Select(pi => pi.Name)
.Concat(fields.Select(pi => pi.Name)).ToArray());
haveOutputHeader = true;
}
yield return String.Join(delimiter,
properties.Select(pi => pi.GetValue(item, null).ToString())
.Concat(fields.Select(fi => fi.GetValue(item).ToString())).ToArray());
}
The above code only ever performs a GetProperties and GetFields once per group of records--also, because of this, there's no need to explicitly sort the properties and fields as was #Frederik's suggestion.
#astander has already given you an answer on the Type t = f != null ? f.FieldType : p.PropertyType; question, so I will leave that one out. Regarding getting the values into the correct columns, I don't know wheter reflection guarantees to list the members of a type in a specific order, but you can guarantee it by sorting the list before using it (using Linq):
MemberInfo[] members = typeof(Item).GetMembers(BindingFlags.Public | BindingFlags.Instance);
IEnumerable<MemberInfo> sortedMembers = members.OrderBy(m => m.Name);
foreach (MemberInfo member in sortedMembers)
{
// write info to file
}
Or if you prefer a non-Linq approach (works with .NET Framework 2.0):
MemberInfo[] members = typeof(Item).GetMembers(BindingFlags.Public | BindingFlags.Instance);
Array.Sort(members, delegate(MemberInfo x, MemberInfo y){
return x.Name.CompareTo(y.Name);
});
foreach (MemberInfo member in members)
{
// write info to file
}
Just to add some thoughts re the accepted answer, in particular for large data volumes:
PropertyInfo etc can be unnecessarily slow; there are ways to avoid this, for example using HyperDescriptor or other dynamic code
rather than building lots of intermediate strings, it may be more efficient to write output directly to a TextWriter
As a tweaked version that adopts these approaches, see below; note that I haven't enabled HyperDescriptor in this example, but that is just:
HyperTypeDescriptionProvider.Add(typeof(YourType));
Anyway...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
static class Program {
static void Main() { // just some test data...
var data = new[] { new { Foo = "abc", Bar = 123 }, new { Foo = "def", Bar = 456 } };
Write(data, Console.Out, true, "|");
}
public static void Write<T>(IEnumerable<T> items, TextWriter output, bool writeHeaders, string delimiter) {
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
foreach (T item in items) {
bool firstCol = true;
if (writeHeaders) {
foreach (PropertyDescriptor prop in properties) {
if (firstCol) {
firstCol = false;
} else {
output.Write(delimiter);
}
output.Write(prop.Name);
}
output.WriteLine();
writeHeaders = false;
firstCol = true;
}
foreach (PropertyDescriptor prop in properties) {
if (firstCol) {
firstCol = false;
} else {
output.Write(delimiter);
}
output.Write(prop.Converter.ConvertToString(prop.GetValue(item)));
}
output.WriteLine();
}
}
}

Categories