是否要求泛型参数包含一个名为C#的特定字符串的属性?

是否要求泛型参数包含一个名为C#的特定字符串的属性?,c#,generics,C#,Generics,假设我有两门课: public class Account { public string Name{get;set;} } public class Account2 { public string Name2{get;set;} } 我想编写一个通用方法,它将接受这些帐户中的任何一个,并对Name和Name2执行完全相同的操作。像这样 public static void ProcessAccountNames<T>(List<T> accounts

假设我有两门课:

public class Account
{
    public string Name{get;set;}
}
public class Account2
{
    public string Name2{get;set;}
}
我想编写一个通用方法,它将接受这些帐户中的任何一个,并对Name和Name2执行完全相同的操作。像这样

public static void ProcessAccountNames<T>(List<T> accounts, string varName) where T: class 
{
    var name = account.GetType().GetProperty(varName).GetValue(account);
    ...
    ...
}
publicstaticvoidprocessaccountnames(列出帐户,字符串varName),其中T:class
{
var name=account.GetType().GetProperty(varName).GetValue(account);
...
...
}
那我就可以打电话了

ProcessAccountNames<Account>(myAccountList, "Name");
ProcessAccountNames<Account2>(myAccount2List, "Name2");
ProcessAccountNames(myAccountList,“名称”);
ProcessAccountNames(myAccount2List,“Name2”);

我想知道在方法签名中是否有任何方法可以指定类型T必须包含名为varName的属性。谢谢

正如Johnathan所说,使用一个界面:

public interface INameable
{
     string Name { get; }
}
然后,对于第二个类,其中Name2是属性的名称,添加一个name属性,该属性返回Name2作为其get值

然后在通用签名上添加

where T : class, INameable
编辑


Johnathan的答案可能是您想要的,尽管它并没有严格按照您要求的方式进行操作。

正如Johnathan所说,使用界面:

public interface INameable
{
     string Name { get; }
}
然后,对于第二个类,其中Name2是属性的名称,添加一个name属性,该属性返回Name2作为其get值

然后在通用签名上添加

where T : class, INameable
编辑


Johnathan的答案可能是你想要的,尽管它并没有严格按照你要求的方式进行。

你可以使用以下表达式:

public static void ProcessAccountNames<T>(List<T> accounts, Expression<Func<T, string>> propSelector) where T: class 
{
    string propName = ((MemberExpression)propSelector.Body).Member.Name;
    var name = account.GetType().GetProperty(propName).GetValue(account);
    ...
    ...
}
尽管这可能被滥用,例如,
x=>“某些字符串”
导致异常

另一种方法是使用
nameof
,这将增加一些编译器安全性:

ProcessAccountNames(myAccountList, nameof(Account.Name));
唯一100%类型安全的方法是根据Chad的回答添加接口并实现转发属性


另一种选择是使用代理:

public static void ProcessAccountNames<T>(List<T> accounts, Func<T, string> getName) where T: class
{
    var name = getName(account);
    ...
    ...
}
或者,您可以提供一个完全不同的函数来检索名称,而不限于属性访问:

ProcessAccountNames(myAccountList, x => "Some Name");

您可以使用以下表达式:

public static void ProcessAccountNames<T>(List<T> accounts, Expression<Func<T, string>> propSelector) where T: class 
{
    string propName = ((MemberExpression)propSelector.Body).Member.Name;
    var name = account.GetType().GetProperty(propName).GetValue(account);
    ...
    ...
}
尽管这可能被滥用,例如,
x=>“某些字符串”
导致异常

另一种方法是使用
nameof
,这将增加一些编译器安全性:

ProcessAccountNames(myAccountList, nameof(Account.Name));
唯一100%类型安全的方法是根据Chad的回答添加接口并实现转发属性


另一种选择是使用代理:

public static void ProcessAccountNames<T>(List<T> accounts, Func<T, string> getName) where T: class
{
    var name = getName(account);
    ...
    ...
}
或者,您可以提供一个完全不同的函数来检索名称,而不限于属性访问:

ProcessAccountNames(myAccountList, x => "Some Name");

作为旁注:在名称上加垫片:for
Account2
:显式接口实现:
string INameable.name=>Name2作为旁注:填充名称:对于
Account2
:显式接口实现:
字符串不可测量。名称=>Name2Func
而不是expression(
expression
)会更好@fooiey@GuruStron是的,关于使用
string
而不是
object
你是对的。我已经用一个替代的实现更新了答案,它使用了委托而不是表达式。谢谢大家。答案真的很有帮助。不过,我认为这最符合我的要求。根据OP在讨论中所描述的内容,我认为
Func
而不是expression(
expression
)会更好@fooiey@GuruStron是的,关于使用
string
而不是
object
你是对的。我已经用一个替代实现更新了答案,该实现使用委托而不是表达式。