是否要求泛型参数包含一个名为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
:显式接口实现:字符串不可测量。名称=>Name2谢谢大家。答案真的很有帮助。不过,我认为这最符合我的要求。根据OP在讨论中所描述的内容,我认为Func
而不是expression(expression
)会更好@fooiey@GuruStron是的,关于使用string
而不是object
你是对的。我已经用一个替代的实现更新了答案,它使用了委托而不是表达式。谢谢大家。答案真的很有帮助。不过,我认为这最符合我的要求。根据OP在讨论中所描述的内容,我认为Func
而不是expression(expression
)会更好@fooiey@GuruStron是的,关于使用string
而不是object
你是对的。我已经用一个替代实现更新了答案,该实现使用委托而不是表达式。