如何将对象属性传递给泛型函数

时间:2014-08-31 07:30:31

标签: c# generics

我正在尝试创建一个接受对象属性并返回对象属性的函数。 如何将属性值放入此特定函数中,以便此函数只接受对象的特定属性而不是整个对象?

class Program
{

  public T MapFrom<T,V>(T SourceObject.property, V DestinationObject.Property) 
  //Not able to achieve this//
  {
    // Code to Map Property
  }


  // Here I want to specifically pass only one property of Object , not the entire one
  ProgramClassObject.MapFrom<Details,Person>(Details.FirstName,Person.FName)

  }  
}

// Class Containing Property
class Details
{
  public string FirstName { get; set;}           
}

// Class Containing Property
class Person
{
  public string FName { get; set;}           
}

2 个答案:

答案 0 :(得分:1)

听起来你正在寻找的是expression。这就是像Entity Framework这样的库有效地“解析”它们传递的代码的方式。

首先,您可以通过此方法从表达式中获取PropertyInfo。我将在下面解释如何使用它,所以请耐心等待。

public static PropertyInfo GetPropertyInfo<TIn, TOut>(Expression<Func<TIn, TOut>> PropertyExpression)
{
    MemberExpression memberExpr;
    switch (PropertyExpression.Body.NodeType)
    {
        case ExpressionType.MemberAccess:
            memberExpr = (MemberExpression)PropertyExpression.Body;
            break;
        case ExpressionType.Convert:
            memberExpr = (MemberExpression)((UnaryExpression)PropertyExpression.Body).Operand;
            break;
        default:
            throw new NotSupportedException();
    }

    var property = (PropertyInfo)memberExpr.Member;
    return property;
}

然后,该方法将成为这样的。我已经冒昧地确保这里的数据类型相同,但如果您愿意,可以将TOut更改为object。我根据您的MapFrom名称做了这件事,这让我相信这些属性是为了直接“沟通”。

public T MapFrom<T, V, TOut>(Expression<Func<T, TOut>> Source, Expression<Func<V, TOut>> Destination)
{
    var sourceProperty = GetPropertyInfo<T, TOut>(Source);
    var destinationProperty = GetPropertyInfo<V, TOut>(Destination);

    // Use those
    // They're PropertyInfo instances, so it should be pretty easy to handle them however you would have expected to.
}

一旦你完成了所有这些,

var ret = MapFrom<Person, Details, string>(c => c.FName, c => c.FirstName);

可以通过使用通用类型的主类来清除签名,因为您不必指定任何类型参数,并且将推断出string。在现实世界的情况下,这可能是你想做的事情,特别是因为你似乎再次映射价值。

答案 1 :(得分:1)

您可以手动执行,也可以使用某些库(请参阅注释,有人提到它)。

如果仍想自己实现:

准备一些有用的Expression扩展程序:

public static B GetProperty<T, B>(this Expression<Func<T, B>> propertySelector, T target) where T : class
{
    if (target == null)
    {
        throw new ArgumentNullException("target");
    }

    if (propertySelector == null)
    {
        throw new ArgumentNullException("propertySelector");
    }

    var memberExpression = propertySelector.Body as MemberExpression;
    if (memberExpression == null)
    {
        throw new NotSupportedException("Only member expression is supported.");
    }

    var propertyInfo = memberExpression.Member as PropertyInfo;
    if (propertyInfo == null)
    {
        throw new NotSupportedException("You can select property only. Currently, selected member is: " +
                                        memberExpression.Member);
    }

    return (B)propertyInfo.GetValue(target);
}

public static void SetProperty<T, B>(this Expression<Func<T, B>> propertySelector, T target, B value)
{
    SetObjectProperty(target, propertySelector, value);
}

public static void SetObjectProperty<T, B>(T target, Expression<Func<T, B>> propertySelector, object value)
{
    if (target == null)
    {
        throw new ArgumentNullException("target");
    }

    if (propertySelector == null)
    {
        throw new ArgumentNullException("propertySelector");
    }

    var memberExpression = propertySelector.Body as MemberExpression;
    if (memberExpression == null)
    {
        throw new NotSupportedException("Cannot recognize property.");
    }

    var propertyInfo = memberExpression.Member as PropertyInfo;
    if (propertyInfo == null)
    {
        throw new NotSupportedException("You can select property only. Currently, selected member is: " + memberExpression.Member);
    }

    propertyInfo.SetValue(target, value);
}

MapFrom实施:

public static void MapFrom<TObject, TTarget, TProp>(TObject source, TTarget dest,
    Expression<Func<TObject, TProp>> sourceSelector, Expression<Func<TTarget, TProp>> targetSelector)
          where TObject : class where TTarget : class
{
    var sourceValue = sourceSelector.GetProperty(source);
    targetSelector.SetProperty(dest, sourceValue);
}

用法:

programClassObject.MapFrom(details, person, det => det.FirstName, per => per.FName);
相关问题