将属性作为参数的泛型函数
本文关键字:泛型 函数 参数 属性 | 更新日期: 2023-09-27 18:32:31
我想写一个泛型函数,它接受一个对象和这个对象的一系列属性。在函数中,我想选择一个新的匿名对象,它只是传入对象的那些属性。
我想做这样的事情:
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。
定义匿名类型实际上非常复杂,并且尝试仅使用名称来执行此操作有些挑战性。基本上你想要的东西已经存在,但在常规 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");
你可以将它们作为lambda传递:
GetNewClass (testObj, ()=>StringHere, ()=> ANumber);
并有一个签名GetNewClass
喜欢
void GetNewClass (object, Expression<Func<object>> expr0, Expression<Func<object>> expr1);
然后,您可以非常轻松地获得该物业。
您可以使用 Linq 表达式来实现这一点。
(注意:您可能需要修改下面的代码片段中的一些内容,这是我的帽子顶部):
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();
}
}
此代码段演示如何获取属性的名称和值。可以这样称呼:
getClass(someObj, obj => obj.SomeProperty, obj.SomeOtherProperty);