0

What I'm trying to do is generalize making repositories using AutoFixture and Moq. I have a method called 'add' that adds fake records to a list. The list is called records and is global to the class. The generic M is a model to be mocked. The method returns 'this' so the method can be chained.

public Repo<M> add(string prop, string val) {
    var a = fixture.Build<M>().With(m => m.GetProperty(prop), val).Create();
    records.Add(a);
    return this;
}

with the extension class (I found this searching SO):

public static class MyExtensions
{
    public static object GetProperty<T>(this T obj, string name) where T : class
    {
        Type t = typeof(T);
        return t.GetProperty(name).GetValue(obj, null);
    }
}

The error I'm getting is "ArgumentException occurred in Ploeh.AutoFixture.dll".

My question is: How can one pass a property of a generic object in as a parameter on a method when the model is unknown at compile time?

Aaron Gates
  • 469
  • 4
  • 15
  • 1
    As a sidenote, your `add` method should be named `Add` instead, according to the [naming guidelines](https://msdn.microsoft.com/en-us/library/vstudio/ms229043(v=vs.100).aspx). – dcastro Sep 11 '15 at 20:13

2 Answers2

4

With method requires Expression<Func<T, TProperty>> parameter not PropertyInfo.

You can change your add method to take Expression<Func<T, TProperty>> instead of string :

public Repo<M> add<T>(Expression<Func<M, T>> propertyPicker, T val) 
{
   var a = fixture.Build<M>().With(propertyPicker, val).Create();
   records.Add(a);
   return this;
}

and this is the usage :

add(foo => foo.Name, "abc");
Arkadiusz K
  • 1,797
  • 1
  • 17
  • 18
0

Many thanks to Arkadiusz for the correct answer. I just want to add this method I added (inspired by several SO posts) to create the Expression so that the usage would be: add("username","me")

private Expression<Func<M,T>> makeExpression<T>(string prop, T val)
{
    var m = Expression.Parameter(typeof(M), "m");
    Expression columnExpr = Expression.Property(m,typeof(M).GetProperty(prop));

    return Expression.Lambda<Func<M, T>>(columnExpr, m);
}

Then, in the add method, I changed propertyPicker to makeExpression(property,val), property being the name of the property as a string.

Aaron Gates
  • 469
  • 4
  • 15
  • `makeExpression` should be `MakeExpression`. [Naming Guidelines](https://msdn.microsoft.com/en-us/library/vstudio/ms229043(v=vs.100).aspx) – Mike B Sep 11 '15 at 23:10
  • You must be aware with approach that you've presented you lose compile-time checking if property exists in `M` class. This implies, if your for example change property name using refactoring tool, that tool will not change property name literal unless they support for searching in string literals. – Arkadiusz K Sep 12 '15 at 06:06