Home > OS >  C# how to get Generic type properties
C# how to get Generic type properties

Time:06-13

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

enter image description here

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;
  • Related