views:

78

answers:

3

I have this C# code that works just fine, which grabs any two fields and puts them in a list for a Drop Down List:

var myDDL = GetDDLValues<Product>( myContact, "contactid", "companyname");

I would like it to take the two string parameters in something other than strings. This would be really nice to do:

GetDDLValues<Product>( myContact, p => p.contactid, p => p.companyname)

This is the code it calls (reflection by sweko Thanks!):

private object GetProperty(object obj, string propertyName)
{
    PropertyInfo pi = obj.GetType().GetProperty(propertyName);
    object value = pi.GetValue(obj, null);
    return value;
}

public  IList<DDLValues> GetDDLValues<T>(IList<T> objectListToMap, 
                         string textProperty, string valueProperty)
{   
    if( objectListToMap != null && objectListToMap.Count > 0)
    {
        Mapper.CreateMap< T, DDLValues>()
              .ForMember( dest => dest.text, 
                           opt => opt.MapFrom(src => textProperty))
              .ForMember( dest => dest.value, 
                           opt => opt.MapFrom(src => valueProperty));
        return Mapper.Map<IList<T>, IList<DDLValues>>(objectListToMap);
    }
    else
    {
        return null;
    }
}
+2  A: 

To build a dynamic query from string:

public class Product 
{ 
    public long ID { get; set; } 
    public string Name { get; set; } 
    public DateTime Date { get; set; } 
} 


static void Main(string[] args) 
{ 
    List<Product> products = (from i in Enumerable.Range(1, 10) 
                          select new Product { ID = i, Name = "product " + i, Date = DateTime.Now.AddDays(-i) }).ToList();  //the test case 

    const string SortBy = "Date";  // to test you can change to "ID"/"Name" 

    Type sortType = typeof(Product).GetProperty(SortBy).PropertyType;     // DateTime 
    ParameterExpression sortParamExp = Expression.Parameter(typeof(Product), "p");    // {p} 
    Expression sortBodyExp = Expression.PropertyOrField(sortParamExp, SortBy);   // {p.DateTime} 
    LambdaExpression sortExp = Expression.Lambda(sortBodyExp, sortParamExp);   //   {p=>p.DateTime} 
    var OrderByMethod = typeof(Enumerable).GetMethods().Where(m => m.Name.Equals("OrderBy") && m.GetParameters().Count() == 2).FirstOrDefault().MakeGenericMethod(typeof(Product), sortType); 
    var result = OrderByMethod.Invoke(products, new object[] { products, sortExp.Compile() }); 
} 
Danny Chen
+1  A: 

If DDLValues has a constructor that takes the text and value properties it should be relatively simple.

IList<DDLValues> GetDDLValues<T>( IList<T> source, Func<T,DDLValues> selector )
    where T : class
{
   return source.Select( selector )
                .ToList();
}

Called as

var ddlList = GetDDLValues( contacts, p => new DDLValues( c.Name, p.ContactID.ToString() ) );

This presumes that DDLValues has a constructor like:

public DDLValues( string text, string value ) { ... }

If you're pulling from the database in your source, then you may also need to materialize the query using ToList() before you apply the selector to ensure it doesn't try to convert the selector into a SQL expression.

tvanfosson
+1  A: 

tvanfosson is right that a Select() is simplest; if you want to use AutoMapper, you want something like this..

public  IList<DDLValues> GetDDLValues<T>(IList<T> objectListToMap, 
                         Func<T, string> textSelector, Func<T, string> valueSelector)
{   
    if( objectListToMap == null || objectListToMap.Count == 0)
        return null;

    Mapper.CreateMap< T, DDLValues>()
          .ForMember( dest => dest.text, 
                       opt => opt.MapFrom(textSelector))
          .ForMember( dest => dest.value, 
                       opt => opt.MapFrom(valueSelector));
    return Mapper.Map<IList<T>, IList<DDLValues>>(objectListToMap);
}
dahlbyk
What a superb side effect: AdmapServ.GetDDLValues<Contact>(ContactRepo.GetIt(), p => p.custid.ToString(), p => p.cucompany ); I can convert the int ToString() as part of the delgate! Fantastic answer!
Dr. Zim