.NET C#如何使泛型中的placehoder成为泛型

.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

更新4:

我发现了如何修复另一个错误:

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; }

}