I am working on .NET 6.0 application. I have class which takes generic dictionary
as parameter
Dictionary<string, TPolicyDictionary> dataPolicyDictionary
where TPolicyDictionary
is class. Now this class has properties that I need to access but unable to recognise since I am expecting property definition to resolve at run time i.e. IsRequire
is one of the property of class DataReadingRule
that I am trying to pass generic method.
public class DataReadingRule
{
public Guid DataReadingRuleId { get; set; }
public bool IsRequire { get; set; }
}
generic class
public class IsRequiredPolicy : BaseConversionValidator, IIsRequiredPolicy
{
public IsRequiredPolicy() { }
public string Text { get; set; }
public string FieldName { get; set; }
public override Task<dynamic> Validate<TPolicyDictionary>(Dictionary<string, TPolicyDictionary> dataPolicyDictionary)
{
try
{
bool isRecordExist = false;
bool isRequired = false;
bool isRecordValid = false;
if (!string.IsNullOrWhiteSpace(FieldName))
{
var policy = dataPolicyDictionary.Where(_ => _.Key == FieldName).Select(x => x.Value).FirstOrDefault();
if (policy.IsRequire) //IsRequire doesn't recognise here
{
isRequired = true;
}
error
CodePudding user response:
The property is not accessible because it is possible to pass instance of any type.
In your case you know that you pass instance of DataReadingRule
but it is also possible to pass instance of object
type and it does not have IsRequire
property - what should compiler do it that case?
If you always know that type DataReadingRule
is passed to Validate()
method then you don't need this method to be generic one (if you can change signature in base class):
public override Task<dynamic> Validate(Dictionary<string, DataReadingRule> dataPolicyDictionary) { // ...}
or you can use constraint (if you can change signature in base class):
public override Task<dynamic> Validate<TPolicyDictionary>(Dictionary<string, TPolicyDictionary> dataPolicyDictionary) where TPolicyDictionary : DataReadingRule { // ...}
If you can't change signature in base class you should check the type of the policy
and cast:
public override Task<dynamic> Validate<TPolicyDictionary>(Dictionary<string, TPolicyDictionary> dataPolicyDictionary)
{
try
{
bool isRecordExist = false;
bool isRequired = false;
bool isRecordValid = false;
if (!string.IsNullOrWhiteSpace(FieldName))
{
var policy = dataPolicyDictionary.Where(_ => _.Key == FieldName).Select(x => x.Value).FirstOrDefault();
if (policy is DataReadingRule dataReadingRule)
{
// property is now accessible
if (dataReadingRule.IsRequire)
{
isRequired = true;
}
// ...
}
else
{
// policy is not DataReadingRule
}
}
// ...
}
}
Or if you can create interface:
public interface IRule
{
public bool IsRequire { get; } // add setter if needed
}
Then implement it:
public class DataReadingRule : IRule
{
public Guid DataReadingRuleId { get; set; }
public bool IsRequire { get; set; }
}
And then add constraint (in base class) and your method will be:
public override Task<dynamic> Validate<TPolicyDictionary>(Dictionary<string, TPolicyDictionary> dataPolicyDictionary)
where TPolicyDictionary : IRule // constraint
{
// your code without changes
}
CodePudding user response:
Carry on @Roman suggestion
Put common properties in Base class and extend the classes from it
public class BaseDataRule
{
public bool IsRequire { get; set; }
}
In Abstract class
public abstract ValidationStatus Validate<TPolicyDictionary>(Dictionary<string, TPolicyDictionary> dataPolicyDictionary) where TPolicyDictionary : BaseDataRule;