【问题标题】:Generic function that takes properties as parameters将属性作为参数的通用函数
【发布时间】:2013-09-24 13:28:21
【问题描述】:

我想编写一个通用函数,它接受一个对象和该对象的一系列属性。在函数内部,我想选择一个新的匿名对象,它只是传入对象的那些属性。

我想做这样的事情:

public class SimpleClass
{
    public DateTime ADate {get; set;}
    public string StringHere {get; set;}
    public int ANumber {get; set;}
}

var testObj = new SimpleClass();
// set values here on testObj properties
DoStuffHere(testObj, StringHere, ANumber);

我可以将属性作为字符串传递,然后使用反射从传入的对象中获取属性,但我想知道是否有某种方法可以传递属性本身,这样我就可以获得智能感知和编译时间检查以防止错误的属性名称。我希望我的 getNewClass 函数采用任何类型的对象,并且是通用的。

编辑:我没有返回新的匿名类型。我认为我的函数名称听起来是这样的。我将在内部从指定的 testObj 列表中选择一个新的匿名类型,并从这些属性生成 PDF。

【问题讨论】:

  • 哇返回匿名类型。看起来很有挑战性..也许烤一些IL;另一方面,您可以返回一个字典
  • 如果你的意思不是让getNewClass return 对象,那么我可能误解了这个问题;我在答案的第二部分中添加了

标签: c# .net generics reflection


【解决方案1】:

定义一个匿名类型实际上是非常复杂的,并且尝试仅使用名称来完成它有些挑战。基本上你想要的已经存在,但是在常规 C# 中 - 所以对于单个对象:

var obj = new { testObj.StringHere, testObj.ANumber };

或者对于多个对象:

var projection = from obj in sequence
                 select new { obj.StringHere, obj.ANumber };

这将尽可能简洁。您可以添加一个采用某种Func<,> 的通用方法,但它不会比上述更简洁。

拥有没有用:

var obj = SomeMagicMethod(obj, "StringHere", "ANumber");

因为SomeMagicMethod 只能有效地返回object - 我们的obj 变量将在很大程度上无法使用。


如果您不需要从方法中返回对象,那么您可以使用以下任一方法:

SomeMagicMethod<T>(T value) {
   ...
}
...
SomeMagicMethod(new {testObj.StringHere, testObj.ANumber });

或:

SomeMagicMethod<TFrom, TTo>(TFrom value, Func<TFrom, TTo> selector)
{
    TTo actualVal = selector(value);
    ...
}
...
SomeMagicMethod(testObj, x => new {x.StringHere, x.ANumber });

就我个人而言,我认为第一个更容易 - 第二个中的 func 是多余的。

你也可以只使用反射...

SomeMagicMethod(object obj, params string[] names)
{
    foreach(var name in names) {
       object val = obj.GetType().GetProperty(name).GetValue(obj);
       // ...
    }
}
//...
SomeMagicMethod(testObj, "StringHere", "ANumber");

【讨论】:

  • obj 可能是 dynamic,但仍然不如通常的匿名类型有用,因为您没有得到智能感知结果。
  • 他可以使用动态,但你会失去类型安全,所以这也不会是答案
  • 我已对我的问题进行了编辑。我不希望返回匿名类型。
【解决方案2】:

您可以将它们作为 lambda 传递:

GetNewClass (testObj, ()=>StringHere, ()=> ANumber);

并为GetNewClass 签名

void GetNewClass (object, Expression<Func<object>> expr0, Expression<Func<object>> expr1);

然后您可以很容易地获得该属性。

【讨论】:

  • GetNewClass 会返回什么对调用者有用?它当然不能返回一个整齐打包的匿名类型,正确输入string StringHereint ANumber...
  • 问题不是关于 GetNewClass 如何工作,而是关于传递参数
  • 它将返回一个代表生成的 PDF 的字节流,所以我并不关心。
【解决方案3】:

您可以为此使用 Linq 表达式。

(注意:您可能需要在下面的 sn-p 中修改一些内容,这是我的顶峰):

public void getNewClass(Object testObj, params MemberExpression Fields[])
{
    foreach(MemberExpression field in Fields)
    {
        // Get the name
        var name = field.Member.Name;

        // get the value
        var member= Expression.Convert(field, typeof(object));
        var lambda= Expression.Lambda<Func<object>>(member);
        var fnc= lambda.Compile();

        var value = fnc();
    }
}

这个 sn-p 显示如何获取属性的名称和值。可以这样调用:

getClass(someObj, obj => obj.SomeProperty, obj.SomeOtherProperty);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-29
    • 2016-09-29
    • 2019-09-20
    • 1970-01-01
    相关资源
    最近更新 更多