Just a quickie before the weekend rolls in...
I have a Method with the following signature, that I need to invoke:
public interface IObjectProvider<T>
{
T Get(Predicate<T> condition);
}
This will provide me with a T from whatever kind of source, that meets the predicate criteria.
Now, this has to be called from a context where all I have is the following:
//the actual predicate that's going to be evaluated
var predicate = predicateProperty.GetValue(invocation.InvocationTarget, null);
//The type that should go into the call as type param
Type relationTargetType = relationDefinition.RelatedType;
As you might guess, the compiler won't let me use the predicate variable as parameter. What I need to do is convert this object into a Predicate, but Generic type params must be compile-time-constant, so this won't work.
I've started messing around with this, but no success so far:
Type genericPredicateType = typeof(Predicate<>);
Type specificPredicateType= genericPredicateType.MakeGenericType(relationTargetType);
Convert.ChangeType(predicate, specificPredicateType)
How on earth can I mash this up?
EDIT: I thought this was a rather use-case-agnostic question, but obviously I was wrong. So, since there is such a fuss as to what I do, what I have and why and whatnot, here's a lot more background info. I am trying to resolve relations between objects in a Proxy (Castle Dynamic Proxy). The following Snippet should explain the kind of relation I want to depict:
public class Order
{
public virtual int Id { get; set; } // OR-Mapped
public virtual DateTime OrderDate { get; set; } // OR-Mapped
[RelatedObject(typeof(Address), "DeliveryAddressPredicate")]
public virtual Address DeliveryAddress { get; set; }
public Predicate<Address> DeliveryAddressPredicate
{
get { return new Predicate<Address>(a => OrderDate >= a.ValidFrom && OrderDate <= a.ValidTo); }
}
}
public class Address
{
public virtual DateTime ValidFrom { get; set; } // OR-Mapped
public virtual DateTime ValidTo { get; set; } // OR-Mapped
//Not OR-Mapped
[RelatedList(typeof(Order), "OrdersPredicate")]
public virtual IList<Order> Orders { get; set; }
public Predicate<Order> OrdersPredicate
{
get { return new Predicate<Order>(o => o.OrderDate >= ValidFrom && o.OrderDate <= ValidTo); }
}
To sum it up, this is supposed to become a Fuzzy OR-Mapping, meant to extend NHibernate in a project or two.
How did I mean to get this to work? The address is proxied, and when a call to a property with one of my CustomAttributes is made, i use DynamicProxy's IInterceptor interface to resolve the relation. The main problem is that this resolving has to happen in the IInterceptor.Intercept() Method which has only one Param (see here), and I have no generic type param available. So, in the end it all boils down to a simple .Net question again: I have a Type stored in a variable and a Method that has to be called with a parameter generic of the aforesaid type...
Sorry for any mistakes made (like calling var a Type - man that was a rough one), it's been quite a day ;-)
You have some IObjectProvider<T>. If T is a type know at compile-time, you can just use a cast. For example, if T was Foo:
IObjectProvider<Foo> provider = …;
var predicate = (Predicate<Foo>)predicateProperty.GetValue(
invocation.InvocationTarget, null);
Foo item = provider.Get(predicate);
EDIT: It seems you don't know T at compile time. This means you have two options:
Use dynamic:
object provider = …
object predicate = predicateProperty.GetValue(
invocation.InvocationTarget, null);
object item = ((dynamic)provider).Get((dynamic)predicate);
Use reflection:
object provider = …;
object predicate = predicateProperty.GetValue(
invocation.InvocationTarget, null);
var getMethod = provider.GetType().GetMethod("Get");
object item = getMethod.Invoke(provider, new[] { predicate });
This question shows a lot of confusion about types, var etc.
This is a meaningless sentence
It is of type var and GetValue turned it into an object.
I think you are saying
I have some code that needs a Predicate<T>
You have some code (that you don't show us) that returns an Object. And want somehow to coerce that return value into a Predicate<T>. If the returned object is a Predicate<T> then simply go (Predicate<T>)retobj - and you are done. If it's not a type that can be cast to Predicate<T> then no amount of jiggling will make it into a Predicate<T>.
I do this way
public T CastToType<T>(object objType, T type) where T : class
{
var cast = objType as T;
if(cast == null)
throw new InvalidCastException();
return cast;
}
And like this
var test = CastToType(objType, new ArrayList());
test will be have ArrayList type
Related
I want to make this code shorter, via passing the type as a parameter to targetUnitOfWork.Query.
There are two types SomeListItem and SomeList. And depending on the actual type I have to call either Query<SomeListItem> or Query<SomeList> as it is shown below.
Type typeName = targetClassInfo.ClassType;
if (typeName.Equals(typeof(SomeListItem)))
{
target = targetUnitOfWork
.Query<SomeListITem>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
else if (typeName.Equals(typeof(SomeList)))
{
target = targetUnitOfWork
.Query<SomeList>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
else
{
target = targetClassInfo.CreateNewObject(targetUnitOfWork);
}
How can I solve this task?
Preface
We will not cover in this answer the design decision made by the authors of the code. It's only worth to say that this kind of heterogeneous generics should be left to pattern matching mechanism instead of polymorphic one.
Motivation
Either way, there are plenty of cases where you want to dynamically put generic types and invoke methods in the chain. It's mostly done in projects serving libraries and frameworks for later usage, where parameters are inherited from the user input, or they come lately to the project as an extension by the developers.
Reflection
Luckily, .NET Framework (and Core as well, the code bellow is .NET Framework) provides a rich Reflection library where you can do your metaprogramming model.
The Reflection library provides a way to introspect the program, compromising the static typization in favor of dynamic one e.g. to find a method by its name, because it comes from the user input. It's not its sole purpose, but we will use it this way.
Action in code
In our scenario, we need to call the Query<T> method with arbitrary <T> which comes from the user input. So let's define a function that will serve this functionality. We will call it Test:
static void Test(Type type, TestGenerics testGenerics, String otherObjectName)
It receives the System.Type, an object in our case TestGenerics and a String to test the name property as in the question.
Our TestGenerics object is a fake class that mimics the question's semantics:
class TestGenerics
{
public IEnumerable<T> Query<T>() where T : new()
{
return Enumerable.Repeat(new T(), 10);
}
}
First of all, we need to find the Query method by name. Since it's the one and only method named this way (no overloads) we can safely use FirstOrDefault:
Object enumerable = testGenerics.GetType().GetMethods().FirstOrDefault(m => m.Name == "Query")
But we cannot invoke it directly, as it accepts not only arguments, but generic parameters as well. We can provide them, by providing Type to MakeGenericMethod(Type) reflection's method:
.MakeGenericMethod(type)
And then we are ready to Invoke it without arguments (as it does not accept any), but we need to specify the object it will be invoked from (in our case testGenerics):
.Invoke(testGenerics, null);
Cool so far, there are the dragons to come here, because we need now to build the i => i.name == otherObjectName lambda. The Where method from IEnumerable<T> extensions (in fact, it's a static method in System.Linq.Enumerable) receives a Func<T, R> instead of Predicate<T>, so we need to build one:
Type predicateType = typeof(Func<,>).MakeGenericType(type, typeof(bool));
This builds Func<,> e.g. a Func type with two generic parameters. The first is the type passed, and the second is boolean to mimic a predicate by function.
Now we need to build the lambdas left side by making a parameter of the given type:
ParameterExpression predParam = Expression.Parameter(type, "i");
And getting the field name from it them:
Expression left = Expression.Field(predParam, type.GetField("name"));
And the right side of the expressions is the name we will compare it with:
Expression right = Expression.Constant(otherObjectName, typeof(string));
Building the whole lambda is the next step. From the predicate type (Func<T, R>, the equality expression and the predicate param "i"):
LambdaExpression lambda = Expression.Lambda(predicateType, Expression.Equal(left, right), predParam);
Now we need to find the Where method. It's in the class containing all the extension methods and not in the IEnumerable interface:
IEnumerable<MethodInfo> methodsEnumerable = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public);
MethodInfo where = methodsEnumerable.Where(m => m.GetParameters().Length == 2).FirstOrDefault(m => m.Name == "Where");
But this is a generic method, receiving the type from the input, so we need to do this as well:
MethodInfo genericWhere = where.MakeGenericMethod(type);
Since it is a static method, the object must be passed as an argument (as for the semantics of an extension method). The first argument in the object array is the extension interface (IEnumerable e.g. the return type of Query) and the second argument is the above lambda - compiled:
Object response = genericWhere.Invoke(enumerable, new[] {enumerable, lambda.Compile()});
And here we will stop with the example. You will need to tweak it for your case and add the other method calls. It's very verbose and ugly as well, but will work for any kind of objects containing the name field. In bigger scenarios, if you don't couple to a certain field hardcoded, it will work for wide variety of inputs. The same way how frameworks works with our code.
The full example you can find below:
class TypeOne
{
public string name;
}
class TypeTwo
{
public string name;
}
internal class Program
{
public static void Main(string[] args)
{
Test(typeof(TypeOne), new TestGenerics(), "John");
Test(typeof(TypeTwo), new TestGenerics(), "Smith");
}
static void Test(Type type, TestGenerics testGenerics, String otherObjectName)
{
Object enumerable = testGenerics.GetType().GetMethods().FirstOrDefault(m => m.Name == "Query")
.MakeGenericMethod(type)
.Invoke(testGenerics, null);
Type predicateType = typeof(Func<,>).MakeGenericType(type, typeof(bool));
ParameterExpression predParam = Expression.Parameter(type, "i");
Expression left = Expression.Field(predParam, type.GetField("name"));
Expression right = Expression.Constant(otherObjectName, typeof(string));
LambdaExpression lambda = Expression.Lambda(predicateType, Expression.Equal(left, right), predParam);
IEnumerable<MethodInfo> methodsEnumerable = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public);
MethodInfo where = methodsEnumerable.Where(m => m.GetParameters().Length == 2).FirstOrDefault(m => m.Name == "Where");
MethodInfo genericWhere = where.MakeGenericMethod(type);
Object response = genericWhere.Invoke(enumerable, new[] {enumerable, lambda.Compile()});
Console.WriteLine(response);
}
}
class TestGenerics
{
public IEnumerable<T> Query<T>() where T : new()
{
return Enumerable.Repeat(new T(), 10);
}
}
Why don't use generic method like this:
private void SomeMethod<T>()
{
target = targetUnitOfWork
.Query<T>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
Then you can call SomeMethod<SomeList>() or SomeMethod<SomeListItem>()
This is what you want to do, right?
class Program
{
static void Main(string[] args)
{
List<object> listOfObjects = new List<object>() { new Item(), new Dog(), new Cat(), new Human() };
Dog martin = GetFirstOrDefault<Dog>(listOfObjects);
}
static T GetFirstOrDefault<T>(List<object> listOfObjects)
{
return (T)listOfObjects.Where(x => x.GetType() == typeof(T)).FirstOrDefault();
}
}
class Item
{
public string Name { get; set; }
public string Color { get; set; }
}
class Dog
{
public string Name { get; set; }
public int Age { get; set; }
}
class Cat
{
public string Name { get; set; }
public int Age { get; set; }
}
class Human
{
public string Name { get; set; }
public DateTime Birth { get; set; }
}
Things are only going to get complicated (messy?) from here on.
Ok, so first two queries are same. So, you might go for a generic method. Something of this sort:
public IEnumerable<T> GetListTarget<T>(bool applyWhere) // You will need to add an constraint here that is applicable to both classes. Only then compiler will be able to understand the properties you are using in the where method
{
if (applyWhere)
{
return targetUnitOfWork
.Query<T>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
else
{
return targetClassInfo.CreateNewObject(targetUnitOfWork);
}
}
The project I'm working on needs some simple audit logging for when a user changes their email, billing address, etc. The objects we're working with are coming from different sources, one a WCF service, the other a web service.
I've implemented the following method using reflection to find changes to the properties on two different objects. This generates a list of the properties that have differences along with their old and new values.
public static IList GenerateAuditLogMessages(T originalObject, T changedObject)
{
IList list = new List();
string className = string.Concat("[", originalObject.GetType().Name, "] ");
foreach (PropertyInfo property in originalObject.GetType().GetProperties())
{
Type comparable =
property.PropertyType.GetInterface("System.IComparable");
if (comparable != null)
{
string originalPropertyValue =
property.GetValue(originalObject, null) as string;
string newPropertyValue =
property.GetValue(changedObject, null) as string;
if (originalPropertyValue != newPropertyValue)
{
list.Add(string.Concat(className, property.Name,
" changed from '", originalPropertyValue,
"' to '", newPropertyValue, "'"));
}
}
}
return list;
}
I'm looking for System.IComparable because "All numeric types (such as Int32 and Double) implement IComparable, as do String, Char, and DateTime." This seemed the best way to find any property that's not a custom class.
Tapping into the PropertyChanged event that's generated by the WCF or web service proxy code sounded good but doesn't give me enough info for my audit logs (old and new values).
Looking for input as to if there is a better way to do this, thanks!
#Aaronaught, here is some example code that is generating a positive match based on doing object.Equals:
Address address1 = new Address();
address1.StateProvince = new StateProvince();
Address address2 = new Address();
address2.StateProvince = new StateProvince();
IList list = Utility.GenerateAuditLogMessages(address1, address2);
"[Address] StateProvince changed from
'MyAccountService.StateProvince' to
'MyAccountService.StateProvince'"
It's two different instances of the StateProvince class, but the values of the properties are the same (all null in this case). We're not overriding the equals method.
IComparable is for ordering comparisons. Either use IEquatable instead, or just use the static System.Object.Equals method. The latter has the benefit of also working if the object is not a primitive type but still defines its own equality comparison by overriding Equals.
object originalValue = property.GetValue(originalObject, null);
object newValue = property.GetValue(changedObject, null);
if (!object.Equals(originalValue, newValue))
{
string originalText = (originalValue != null) ?
originalValue.ToString() : "[NULL]";
string newText = (newText != null) ?
newValue.ToString() : "[NULL]";
// etc.
}
This obviously isn't perfect, but if you're only doing it with classes that you control, then you can make sure it always works for your particular needs.
There are other methods to compare objects (such as checksums, serialization, etc.) but this is probably the most reliable if the classes don't consistently implement IPropertyChanged and you want to actually know the differences.
Update for new example code:
Address address1 = new Address();
address1.StateProvince = new StateProvince();
Address address2 = new Address();
address2.StateProvince = new StateProvince();
IList list = Utility.GenerateAuditLogMessages(address1, address2);
The reason that using object.Equals in your audit method results in a "hit" is because the instances are actually not equal!
Sure, the StateProvince may be empty in both cases, but address1 and address2 still have non-null values for the StateProvince property and each instance is different. Therefore, address1 and address2 have different properties.
Let's flip this around, take this code as an example:
Address address1 = new Address("35 Elm St");
address1.StateProvince = new StateProvince("TX");
Address address2 = new Address("35 Elm St");
address2.StateProvince = new StateProvince("AZ");
Should these be considered equal? Well, they will be, using your method, because StateProvince does not implement IComparable. That's the only reason why your method reported that the two objects were the same in the original case. Since the StateProvince class does not implement IComparable, the tracker just skips that property entirely. But these two addresses are clearly not equal!
This is why I originally suggested using object.Equals, because then you can override it in the StateProvince method to get better results:
public class StateProvince
{
public string Code { get; set; }
public override bool Equals(object obj)
{
if (obj == null)
return false;
StateProvince sp = obj as StateProvince;
if (object.ReferenceEquals(sp, null))
return false;
return (sp.Code == Code);
}
public bool Equals(StateProvince sp)
{
if (object.ReferenceEquals(sp, null))
return false;
return (sp.Code == Code);
}
public override int GetHashCode()
{
return Code.GetHashCode();
}
public override string ToString()
{
return string.Format("Code: [{0}]", Code);
}
}
Once you've done this, the object.Equals code will work perfectly. Instead of naïvely checking whether or not address1 and address2 literally have the same StateProvince reference, it will actually check for semantic equality.
The other way around this is to extend the tracking code to actually descend into sub-objects. In other words, for each property, check the Type.IsClass and optionally the Type.IsInterface property, and if true, then recursively invoke the change-tracking method on the property itself, prefixing any audit results returned recursively with the property name. So you'd end up with a change for StateProvinceCode.
I use the above approach sometimes too, but it's easier to just override Equals on the objects for which you want to compare semantic equality (i.e. audit) and provide an appropriate ToString override that makes it clear what changed. It doesn't scale for deep nesting but I think it's unusual to want to audit that way.
The last trick is to define your own interface, say IAuditable<T>, which takes a second instance of the same type as a parameter and actually returns a list (or enumerable) of all of the differences. It's similar to our overridden object.Equals method above but gives back more information. This is useful for when the object graph is really complicated and you know you can't rely on Reflection or Equals. You can combine this with the above approach; really all you have to do is substitute IComparable for your IAuditable and invoke the Audit method if it implements that interface.
This project on github checks nearly any type of property and can be customized as you need.
You might want to look at Microsoft's Testapi It has an object comparison api that does deep comparisons. It might be overkill for you but it could be worth a look.
var comparer = new ObjectComparer(new PublicPropertyObjectGraphFactory());
IEnumerable<ObjectComparisonMismatch> mismatches;
bool result = comparer.Compare(left, right, out mismatches);
foreach (var mismatch in mismatches)
{
Console.Out.WriteLine("\t'{0}' = '{1}' and '{2}'='{3}' do not match. '{4}'",
mismatch.LeftObjectNode.Name, mismatch.LeftObjectNode.ObjectValue,
mismatch.RightObjectNode.Name, mismatch.RightObjectNode.ObjectValue,
mismatch.MismatchType);
}
Here a short LINQ version that extends object and returns a list of properties that are not equal:
usage: object.DetailedCompare(objectToCompare);
public static class ObjectExtensions
{
public static List<Variance> DetailedCompare<T>(this T val1, T val2)
{
var propertyInfo = val1.GetType().GetProperties();
return propertyInfo.Select(f => new Variance
{
Property = f.Name,
ValueA = f.GetValue(val1),
ValueB = f.GetValue(val2)
})
.Where(v => !v.ValueA.Equals(v.ValueB))
.ToList();
}
public class Variance
{
public string Property { get; set; }
public object ValueA { get; set; }
public object ValueB { get; set; }
}
}
You never want to implement GetHashCode on mutable properties (properties that could be changed by someone) - i.e. non-private setters.
Imagine this scenario:
you put an instance of your object in a collection which uses GetHashCode() "under the covers" or directly (Hashtable).
Then someone changes the value of the field/property that you've used in your GetHashCode() implementation.
Guess what... your object is permanently lost in the collection since the collection uses GetHashCode() to find it! You've effectively changed the hashcode value from what was originally placed in the collection. Probably not what you wanted.
Liviu Trifoi solution: Using CompareNETObjects library.
GitHub - NuGet package - Tutorial.
I think this method is quite neat, it avoids repetition or adding anything to classes. What more are you looking for?
The only alternative would be to generate a state dictionary for the old and new objects, and write a comparison for them. The code for generating the state dictionary could reuse any serialisation you have for storing this data in the database.
The my way of Expression tree compile version. It should faster than PropertyInfo.GetValue.
static class ObjDiffCollector<T>
{
private delegate DiffEntry DiffDelegate(T x, T y);
private static readonly IReadOnlyDictionary<string, DiffDelegate> DicDiffDels;
private static PropertyInfo PropertyOf<TClass, TProperty>(Expression<Func<TClass, TProperty>> selector)
=> (PropertyInfo)((MemberExpression)selector.Body).Member;
static ObjDiffCollector()
{
var expParamX = Expression.Parameter(typeof(T), "x");
var expParamY = Expression.Parameter(typeof(T), "y");
var propDrName = PropertyOf((DiffEntry x) => x.Prop);
var propDrValX = PropertyOf((DiffEntry x) => x.ValX);
var propDrValY = PropertyOf((DiffEntry x) => x.ValY);
var dic = new Dictionary<string, DiffDelegate>();
var props = typeof(T).GetProperties();
foreach (var info in props)
{
var expValX = Expression.MakeMemberAccess(expParamX, info);
var expValY = Expression.MakeMemberAccess(expParamY, info);
var expEq = Expression.Equal(expValX, expValY);
var expNewEntry = Expression.New(typeof(DiffEntry));
var expMemberInitEntry = Expression.MemberInit(expNewEntry,
Expression.Bind(propDrName, Expression.Constant(info.Name)),
Expression.Bind(propDrValX, Expression.Convert(expValX, typeof(object))),
Expression.Bind(propDrValY, Expression.Convert(expValY, typeof(object)))
);
var expReturn = Expression.Condition(expEq
, Expression.Convert(Expression.Constant(null), typeof(DiffEntry))
, expMemberInitEntry);
var expLambda = Expression.Lambda<DiffDelegate>(expReturn, expParamX, expParamY);
var compiled = expLambda.Compile();
dic[info.Name] = compiled;
}
DicDiffDels = dic;
}
public static DiffEntry[] Diff(T x, T y)
{
var list = new List<DiffEntry>(DicDiffDels.Count);
foreach (var pair in DicDiffDels)
{
var r = pair.Value(x, y);
if (r != null) list.Add(r);
}
return list.ToArray();
}
}
class DiffEntry
{
public string Prop { get; set; }
public object ValX { get; set; }
public object ValY { get; set; }
}
So what I'm trying to achieve is essentially to pass a type to a method and return an IEnumerable of that type from the method.
This is what I have managed thus far:
class Program
{
static void Main(string[] args)
{
var x = PassType(typeof(Test));
}
public static IEnumerable<dynamic> PassType(Type destType)
{
var testInstance = new Test() { Name = "Greg", Age = 45, IsSomething = false };
var destinationList = ((IEnumerable<object>)Activator.CreateInstance(typeof(List<>).MakeGenericType(new[] { destType }))).ToList();
destinationList.Add(testInstance);
return destinationList;
}
}
public class Test
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsSomething { get; set; }
public Test()
{
}
}
However, this is obviously returning an IEnumerable of type dynamic, I was wondering whether there was a way to return an IEnumerable of type Test
Thanks in advance
Actually what you return is an IEnumerable<TheType>, at least at runtime. However you can´t expect the compiler to infer type-arguments that you provide att runtime. Thus the compiler can´t know of which type the enumerable is, all it knows it that it´s something dynamic. This is why you can´t call any members of that type on the instances within the enumeration.
However in your case a simple generic method will do what you want:
var x = PassType<Test>();
Which needs your method to be similar to this:
IEnumerable<T> PassType<T>() { ...}
If you don´t know that type at compile-time you may use MakeGenericMethod to call the generic method with a type-argument passed at runtime:
var theMethod = typeof(Program).GetMethod("PassType").MakeGenericMethod(typeof(Test));
var x = theMethod.Invoke();
However during compile-time you still have no knowledge on the type, thus x is of type object. As IEnumerable<T> is covariant since .NET 4.0 you could cast this to IEnumerable<object> or IEnumerable<MyBaseClass> if all your types implement MyBaseClass. But you´ll never get an IEnumerable<MyType> at compile-time and call members of that type directly on the instances.
I think you should have a look at Generics in C#.
More info: Generics
I am working on a WCF service and I have run into a bit of a snag mapping my entities to my DTO. Consider the following
namespace Foo.Entities
{
public class Order : IOrder
{
public string Name { get;set; }
public string Address { get;set; }
public IList<ILocation> Locations { get;set; }
}
}
namespace Foo.DTO
{
[DataContract]
public class Order
{
[DataMember]
public string Name { get;set; }
[DataMember]
public string Address { get;set; }
[DataMember]
public List<Location> Locations { get;set; }
}
}
This is all very straightforward: DTO.Order is what I am returning from my endpoint and Entities.Order is what I am using internally (I am using DI / IOC) for business logic, data operations, etc. Since my business layer returns types from the Entities namespace, but the endpoint returns types from the DTO namespace I wrote a small mapping method that will take one type and map it to another type like so:
public TTarget MapObject<TSource, TTarget>(TSource source, TTarget target)
where TSource : class
where TTarget : class
{
foreach (var prop in source.GetType().GetProperties())
{
var targetProp = target.GetType().GetProperty(prop.Name, BindingFlags.Public | BindingFlags.Instance);
if(targetProp == null || !targetProp.CanWrite) continue;
if (prop.PropertyType.GetGenericTypeDefinition() == typeof (IList<>))
{
??
}
else{ targetProp.SetValue(target, prop.GetValue(source)); }
}
return target;
}
I then call this method like so:
factory.MapObject(Entities.DealerOrder, new GTO.DealerOrder())
where Entities.DealerOrder represents an instantiated object that contains data.
Everything works fine until I get to the property of type IList and I am at a loss at how to convert the IList to List. I know what needs to happen but all of the documentation I have read thus far hasn't pointed me in the right direction.
The pseudo is
if (prop.PropertyType.GetGenericTypeDefinition() == typeof (IList<>))
{
var lst = new List<type of targetProp>()
foreach(var val in prop.GetValue())
{
var item = new Location() (I have to figure out this initialization based on the List type of targetProp. In this case it would be List<Location>)
var retval = MapObject(val, item);
lst.Add(retval);
}
targetProp.SetValue(target, lst);
}
I am not sure if what I want to do is even possible. I know that Generics and Reflection don't mix well so if there is a solution it might be overly complex for what I am really trying to accomplish. If worse comes to worse I can put a static method on each of my DTO's that will accept the source type as a parameter and return an instance of the DTO, but I want to avoid having to manually map the fields from the Entity to the DTO if at all possible.
Any help is greatly appreciated.
You can use targetProp.GetGenericArguments()[0]; to get the type of item you want to map your collection content to.
You can use Activator.CreateInstance to create List<T> with T known at runtime at not at compile time.
You can use Activator.CreateInstance to create instance of the type you want to map to.
You can't rely on type inference when calling MapObject anymore. You need to create proper generic method via reflection here too, and call it.
You can't simply call Add on the list, because you don't know what kind of list it is. You can cast it to ICollection and call Add on it instead.
Can't you just use something like AutoMapper? Those are problems people already solved, why don't you use their work?
I was looking at the answer of this question regarding multiple generic types in one container and I can't really get it to work: the properties of the Metadata class are not visible, since the abstract class doesn't have them. Here is a slightly modified version of the code in the original question:
public abstract class Metadata
{
}
public class Metadata<T> : Metadata
{
// Per Ben Voigt's comments, here are the rest of the properties:
public NUM_PARAMS NumParams { get; set; }
public FUNCTION_NAME Name { get; set; }
public List<Type> ParamTypes { get; set; }
public Type ReturnType { get; set; }
//...C
public T Function { get; set; }
public Metadata(T function)
{
Function = function;
}
}
List<Metadata> metadataObjects;
metadataObjects.Add(new Metadata<Func<double,double>>(SomeFunction));
metadataObjects.Add(new Metadata<Func<int,double>>(SomeOtherFunction));
metadataObjects.Add(new Metadata<Func<double,int>>(AnotherFunction));
foreach( Metadata md in metadataObjects)
{
var tmp = md.Function; // <-- Error: does not contain a definition for Function
}
The exact error is:
error CS1061: 'Metadata' does not
contain a definition for 'Function' and no
extension method 'Function' accepting a
first argument of type 'Metadata'
could be found (are you missing a
using directive or an assembly
reference?)
I believe it's because the abstract class does not define the property Function, thus the whole effort is completely useless. Is there a way that we can get the properties?
Update
The basic idea is that I have a genetic program that uses the Metadata of functions (or MetaFunctions) in order to construct expression trees with those functions. The meta data allows me to correctly match the return from one function with the input parameters of another function... it basically turns my functions into legos and the computer can combine them in various ways. The functions are all within the same "domain", so I won't have any problem with randomly mixing and matching them.
I'm storing the Metadata, or MetaFunctions, into a couple of dictionaries:
one has the name of the function as the key.
the other has the number of parameters as the key.
In any case, I just tried to stick as close to the original question as possible... the fundamental problem is the same regardless if I use a List or a Dictionary. I'm also stuck with .NET 3.5 and I won't be able to update to .NET 4.0 for a while.
What would you do with md.Function if you could read it? You can't call it, because you don't know the parameter types. With C# 4.0, you could use dynamic, e.g. foreach (dynamic md in metadataObjects) and then you don't need the Metadata abstract base class. If you just want to access members of Delegate, you could change the abstract base class to an interface which has a Delegate Metadata { get; } property and explicitly implement it in Metadata<T>, then you could access e.g. the function's name.
I think the main problem here is that you are trying to solve a very Dynamic problem with the very Static (but flexible) tools of Generic Programming. So i see two ways for you to go.
Split all your collections along type boundaries, creating a different collection for each type of function you have. This should be possible in your case because you know all the types ahead of time so you will know what types to create.
Embrace the dynamic nature of the problem you are trying to solve and then use the right tools for the job. From what I can tell you want to be able to store a list of 'Functions' and then dynamically decide at run time which ones to call with which arguments. In this case you just need a better model.
I would go with option 2. From my understanding I think that this would be a better model.
public class Variable
{
public Type Type {get; protected set;}
public Object Value {get;protected set;}
public Variable(Object val)
{
Type = val.GetType();
Value = val;
}
public Variable(Type t, Object val)
{
Type = t;
Value = val;
}
}
public class ComposableFunction
{
public NUM_PARAMS NumParams { get; protected set; }
public FUNCTION_NAME Name { get; protected set; }
//our function signature
public List<Type> ParamTypes { get; protected set; }
public Type ReturnType { get; protected set; }
private Delegate Function { get; set; }
public Metadata (Delegate function)
{
Function = function;
}
public bool CanCallWith(params Variable vars)
{
return CanCallWith(vars);
}
public bool CanCallWith(IEnumerable<Variable> vars)
{
using(var var_enum = vars.GetEnumerator())
using(var sig_enum = ParamTypes.GetEnumerator())
{
bool more_vars = false;
bool more_sig =false;
while( (more_sig = sig_enum.MoveNext())
&& (more_vars = var_enum.MoveNext())
&& sig_enum.Current.IsAssignableFrom(var_enum.Current.Type));
if(more_sig || more_vars)
return false;
}
return true;
}
public Variable Invoke(params Variable vars)
{
return Invoke(vars);
}
public Variable Invoke(IEnumerable<Variable> vars)
{
return new Variable(ReturnType, Function.DynamicInvoke(vars.Select(v => v.Value)));
}
}
So now we have a nice model that should fulfill your requirements, and because it takes no generic type parameters you should be able to access all of its functionality when you iterate through a List<ComposableFunction> or whatever.
you are right, the error is because the list thinks it has a bunch of Metadata objects so when you iterate it you get back metadata references, in order to access a property defined in a subclass you need to make sure that the object actually is that subclass and then do the cast.
foreach( Metadata md in metadataObjects)
{
var tmp =((Metadata<Func<double,double>>)md).Function; // but this will obviously fail if the type is incorrect.
}
so here you are really just trading a definite compile time error for a potential run time error (depending on what is in your list). The real question is: What do you want to do with all these different function delegate wrappers? what do you expect the type of your tmp variable to be?
You could also try a type testing solution like this
foreach( Metadata md in metadataObjects)
{
var dd_md = md as Metadata<Func<double,double>>;
var id_md = md as Metadata<Func<int,double>>;
var di_md = md as Metadata<Func<double,int>>;
if(dd_md != null)
{
var tmp1 =dd_md.Function;
}
else if(id_md != null)
{
var tmp2 =id_md.Function;
}
else if(di_md != null)
{
var tmp3 =di_md.Function;
}
//etc....
}
this could also be a viable solution as long as you know exactly what types there will be ahead of time, but its annoying and error prone.