.NET C#如何使泛型中的placehoder成为泛型
更新4: 我发现了如何修复另一个错误:.NET C#如何使泛型中的placehoder成为泛型,c#,.net,.net-core,system.reflection,C#,.net,.net Core,System.reflection,更新4: 我发现了如何修复另一个错误: interface IRule<TEntity> where TEntity : TableEntity, new() interface-IRule 其中tenty:TableEntity,new() 但是,我在将AddressRule添加到Validator类中的规则时遇到了问题 public Validator() { Rules = new List<IRule<TableEntity
interface IRule<TEntity>
where TEntity : TableEntity, new()
interface-IRule
其中tenty:TableEntity,new()
但是,我在将AddressRule添加到Validator类中的规则时遇到了问题
public Validator()
{
Rules = new List<IRule<TableEntity>>();
var addressRule = new AddressRule();
Rules.Add(addressRule);
}
公共验证器()
{
规则=新列表();
var addressRule=新的addressRule();
规则。添加(地址规则);
}
更新3:
现在,我将代码更新为以下内容:
interface IRule<TEntity> where TEntity : TableEntity
{
string TableName { get; }
string Rule { get; }
string SaveToTable { get; }
ReportEntity Handle(TableEntity entity);
TableQuery<TEntity> GetTableQuery();
}
接口单元,其中tenty:TableEntity
{
字符串TableName{get;}
字符串规则{get;}
字符串保存表{get;}
报表实体句柄(TableEntity);
TableQuery GetTableQuery();
}
我指定了TEntity必须是什么类型的类,它删除了第一个错误,但第二个错误仍然存在:
错误CS0310“TEntity”必须是具有公共
无参数构造函数,以便将其用作参数“TElement”
在泛型类型或方法“TableQuery”中
更新2: 在应用Juston.另一个.程序员的建议后,我得到了这个错误
更新: 我正在使用策略模式,我有大量的规则,我需要根据每个规则检查Azure存储表中的所有行
interface IRule where TEntity : TableEntity, new()
{
string TableName { get; } // It could be "ContractAccount", "Bill", "Transaction" etc.
string Rule { get; }
string SaveToTable { get; }
TableQuery<TEntity> TableQuery { get; }
ReportEntity Handle(TableEntity entity);
}
interface-IRule其中tenty:TableEntity,new()
{
字符串TableName{get;}//可以是“ContractAccount”、“Bill”、“Transaction”等。
字符串规则{get;}
字符串保存表{get;}
TableQuery TableQuery{get;}
报表实体句柄(TableEntity);
}
所以规则的实例存在于验证器中
public Validator()
{
Rules = new List<IRule>();
Rules.Add(new AddressRule());
}
公共验证器()
{
规则=新列表();
添加(新地址规则());
}
表实体类(ContractAccount.cs Bill.cs等)将与值IRule.TableName保持相同的名称
这就是ContractAccount的来源
然后在验证器中,我有Validate(),它看起来像:
public async void Validate(CloudStorageAccount storageAccount)
{
var tableClient = storageAccount.CreateCloudTableClient();
//.....
var query = new TableQuery<ContractAccount>(); //<-- I want to replace ContractAccount with something generic
//...
var rows = await tableToBeValidated.ExecuteQuerySegmentedAsync(query, token);
}
//...
}
public异步void验证(CloudStorageAccount-storageAccount)
{
var tableClient=storageAccount.CreateCloudTableClient();
//.....
var query=new TableQuery();/“ContractAccount”;
公共字符串规则=>“电子邮件不能为空”;
公共字符串SaveToTable=>“XXXX”;
public TableQuery TableQuery=>new TableQuery();
公共报表实体句柄(TableEntity)
{
var合同=作为合同账户的实体;
如果(合同==null)
{
抛出新异常($“应为实体类型{TableName},但传入无效实体”);
}
if(string.IsNullOrWhiteSpace(contract.Address))
{
var报告=新报告实体(this.Rule、contract.UserId、contract.AccountNumber、contract.ContractNumber)
{
PartitionKey=contract.UserId,
RowKey=contract.AccountNumber
};
返回报告;
}
返回null;
}
}
如你所见
var query = new TableQuery<ContractAccount>();
var query=new TableQuery();
我需要用如下内容替换硬编码:
var type = Type.GetType(tableName);
var query = new TableQuery<type>();
var type=type.GetType(tableName);
var query=new TableQuery();
但占位符(ContractAccount)将在应用程序运行时更改,可能是
账单、保单、交易等
我不能用这个
<T>
事情
我如何用一个通用的东西来替换ContractAccount
谢谢诸如此类的东西:
var genericType = typeof(TableQuery<>);
Type[] itemTypes = { Type.GetType("MyNamespace.Foo.Entities." + tableName) };
var concretType = genericType.MakeGenericType(itemTypes);
var query = Activator.CreateInstance(concretType);
public abstract class EntityValidationRule {
//Private Fields
private Validator validator;
//Constructors
public EntityValidationRule(String tableName, IEnumerable<String> affectedFields) {
TableName = tableName ?? throw new ArgumentNullException(nameof(tableName));
AffectedFields = affectedFields?.ToArray() ?? Array.Empty<String>();
}
//Public Properties
public String TableName { get; }
public String[] AffectedFields { get; }
public virtual String Description { get; protected set; }
//Public Methods
public Boolean IsValid(DataRow record, ref IErrorDetails errorDetails) {
if (record == null) throw new InvalidOperationException("Programming error in Validator.cs");
if (!Validator.IdentifyerComparer.Equals(record.Table.TableName, TableName)) throw new InvalidOperationException("Programming error in Validator.cs");
String myError = GetErrorMessageIfInvalid(record);
if (myError == null) return true;
errorDetails = CreateErrorDetails(record, myError);
return false;
}
//Protected Properties
public Validator Validator {
get {
return validator;
}
internal set {
if ((validator != null) && (!Object.ReferenceEquals(validator, value))) {
throw new InvalidOperationException("An entity validation rule can only be added to a single validator!");
}
validator = value;
}
}
//Protected Methods
protected virtual IErrorDetails CreateErrorDetails(DataRow record, String errorMessage) {
return new ErrorDetails(record, this, errorMessage);
}
protected abstract String GetErrorMessageIfInvalid(DataRow record);
}
public class TextFieldMustHaveValue : OneFieldRule {
public TextFieldMustHaveValue(String tableName, String fieldName) : base(tableName, fieldName) {
Description = $"Field {FieldName} cannot be empty!";
}
protected override String GetErrorMessageIfInvalid(DataRow record) {
if (String.IsNullOrWhiteSpace(record.Field<String>(FieldName))) {
return Description;
}
return null;
}
}
public sealed class Validator {
//Private Fields
private Dictionary<String, List<EntityValidationRule>> ruleDict;
//Constructors
//The list of all rules we just have somehow...
public Validator(IEnumerable<EntityValidationRule> rules, StringComparer identifyerComparer) {
if (rules == null) throw new ArgumentNullException(nameof(rules));
if (identifyerComparer == null) identifyerComparer = StringComparer.OrdinalIgnoreCase;
IdentifyerComparer = identifyerComparer;
ruleDict = new Dictionary<String, List<EntityValidationRule>>(IdentifyerComparer);
foreach (EntityValidationRule myRule in rules) {
myRule.Validator = this;
List<EntityValidationRule> myRules = null;
if (ruleDict.TryGetValue(myRule.TableName, out myRules)) {
myRules.Add(myRule);
} else {
myRules = new List<EntityValidationRule> { myRule };
ruleDict.Add(myRule.TableName, myRules);
}
}
}
//Public Properties
public StringComparer IdentifyerComparer { get; }
//Public Methods
public Boolean IsValid(DataRow record, ref IErrorDetails[] errors) {
//Check whether the record is null
if (record == null) {
errors = new IErrorDetails[] { new ErrorDetails(record, null, "The given record is null!") };
return false;
}
//Loop through every check and invoke them
List<IErrorDetails> myErrors = null;
IErrorDetails myError = null;
foreach (EntityValidationRule myRule in GetRules(record.Table.TableName)) {
if (myRule.IsValid(record, ref myError)) {
if (myErrors == null) myErrors = new List<IErrorDetails>();
myErrors.Add(myError);
}
}
//Return true if there are no errors
if (myErrors == null) return true;
//Otherwise assign them as result and return false
errors = myErrors.ToArray();
return false;
}
//Private Methods
private IEnumerable<EntityValidationRule> GetRules(String tableName) {
if (ruleDict.TryGetValue(tableName, out List<EntityValidationRule> myRules)) return myRules;
return Array.Empty<EntityValidationRule>();
}
}
var genericType=typeof(TableQuery);
Type[]itemTypes={Type.GetType(“MyNamespace.Foo.Entities.”+tableName)};
var concretType=genericType.MakeGenericType(itemTypes);
var query=Activator.CreateInstance(concretType);
您可以像@Christoph建议的那样使用反射,但在本例中有一种更简单的方法。将TEntity
泛型参数添加到IRule
类中,而不是使用TableName
string属性,并将GetTableQuery
方法添加到类中
interface-IRule
{
字符串规则{get;}
字符串保存表{get;}
报表实体句柄(TableEntity);
TableQuery GetTableQuery();
}
然后,在IRule
实现中添加正确的实体。例如地址规则
公共类地址规则:IRule
{
公共字符串TableName=>“ContractAccount”;
公共字符串规则=>“电子邮件不能为空”;
公共字符串SaveToTable=>“XXXX”;
公共报表实体句柄(TableEntity)
{
var合同=作为合同账户的实体;
如果(合同==null)
{
抛出新异常($“应为实体类型{TableName},但传入无效实体”);
}
if(string.IsNullOrWhiteSpace(contract.Address))
{
var报告=新报告实体(this.Rule、contract.UserId、contract.AccountNumber、contract.ContractNumber)
{
PartitionKey=contract.UserId,
RowKey=contract.AccountNumber
};
返回报告;
}
返回null;
}
公共TableQuery GetTableQuery()
{
返回新的TableQuery();
}
}
现在,在Validate
方法中,可以使用IRule
中的GetTableQuery
方法
public异步void验证(CloudStorageAccount-storageAccount)
{
var tableClient=storageAccount.CreateCloudTableClient();
//.....
var query=rule.GetTableQuery();
//...
var rows=Wait tableToBeValidated.ExecuteQuerySegmentedAsync(查询,令牌);
}
//...
}
我想得越久,就越觉得你需要的是一个通用电气
public abstract class OneFieldRule : EntityValidationRule {
public OneFieldRule(String tableName, String fieldName) : base(tableName, new String[] { fieldName }) {
}
protected String FieldName => AffectedFields[0];
}
public class TextFieldMustHaveValue : OneFieldRule {
public TextFieldMustHaveValue(String tableName, String fieldName) : base(tableName, fieldName) {
Description = $"Field {FieldName} cannot be empty!";
}
protected override String GetErrorMessageIfInvalid(DataRow record) {
if (String.IsNullOrWhiteSpace(record.Field<String>(FieldName))) {
return Description;
}
return null;
}
}
public sealed class Validator {
//Private Fields
private Dictionary<String, List<EntityValidationRule>> ruleDict;
//Constructors
//The list of all rules we just have somehow...
public Validator(IEnumerable<EntityValidationRule> rules, StringComparer identifyerComparer) {
if (rules == null) throw new ArgumentNullException(nameof(rules));
if (identifyerComparer == null) identifyerComparer = StringComparer.OrdinalIgnoreCase;
IdentifyerComparer = identifyerComparer;
ruleDict = new Dictionary<String, List<EntityValidationRule>>(IdentifyerComparer);
foreach (EntityValidationRule myRule in rules) {
myRule.Validator = this;
List<EntityValidationRule> myRules = null;
if (ruleDict.TryGetValue(myRule.TableName, out myRules)) {
myRules.Add(myRule);
} else {
myRules = new List<EntityValidationRule> { myRule };
ruleDict.Add(myRule.TableName, myRules);
}
}
}
//Public Properties
public StringComparer IdentifyerComparer { get; }
//Public Methods
public Boolean IsValid(DataRow record, ref IErrorDetails[] errors) {
//Check whether the record is null
if (record == null) {
errors = new IErrorDetails[] { new ErrorDetails(record, null, "The given record is null!") };
return false;
}
//Loop through every check and invoke them
List<IErrorDetails> myErrors = null;
IErrorDetails myError = null;
foreach (EntityValidationRule myRule in GetRules(record.Table.TableName)) {
if (myRule.IsValid(record, ref myError)) {
if (myErrors == null) myErrors = new List<IErrorDetails>();
myErrors.Add(myError);
}
}
//Return true if there are no errors
if (myErrors == null) return true;
//Otherwise assign them as result and return false
errors = myErrors.ToArray();
return false;
}
//Private Methods
private IEnumerable<EntityValidationRule> GetRules(String tableName) {
if (ruleDict.TryGetValue(tableName, out List<EntityValidationRule> myRules)) return myRules;
return Array.Empty<EntityValidationRule>();
}
}
public interface IErrorDetails {
DataRow Entity { get; }
EntityValidationRule Rule { get; }
String ErrorMessage { get; }
}
public class ErrorDetails : IErrorDetails {
public ErrorDetails(DataRow entity, EntityValidationRule rule, String errorMessage) {
Entity = entity;
Rule = rule;
ErrorMessage = errorMessage;
}
public DataRow Entity { get; }
public EntityValidationRule Rule { get; }
public String ErrorMessage { get; }
}