开发者

C# Function that accepts string parameters: How to refactor to use something strongly typed?

开发者 https://www.devze.com 2023-01-22 12:39 出处:网络
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:

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


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


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


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消