How to call generic function from list of objects - c#

I have a generic list of objects, but the types within the list are all different types. However, when iterating over the list of objects, and then calling a generic function, the type of T defined in the generic is of type Object. How can I get the pattern matching to work so that type of T matches the concrete type of the object being validated? For example, In the contrived example below, when calling Validate on the ValidationService, the line
if(validator is IValidator<T> typedValidator)
always fails because type of T is object, and the physical implementation would be IValidator<Widget> or IValidator<Entity>. How should I change the DemonstrateProblem() method so that the call to validationService.Validate uses the concrete type for the function and not the type of the type as defined in the the List<object>? To make it slightly more complex, my actual code is also asynchronous, so I actually need a return value of Task<IValidationResult<T>>
namespace Contrived
{
public interface IValidator { }
public interface IValidationResult<T> { }
public interface IValidator<T> : IValidator
{
IValidationResult<T> Validate(T entity);
}
public class ValidationResult<T> : IValidationResult<T>
{
public bool IsValid { get; set; }
}
public class Entity
{
public int Id { get; set; }
public string SomeProperty { get; set; }
}
public class EntityValidator : Contrived.IValidator<Entity>
{
public IValidationResult<Entity> Validate(Entity entity)
{
return new ValidationResult<Entity>() { IsValid = true };
}
}
public class Widget
{
public Guid UniqueIdentifier { get; set; }
}
public class WidgetValidator : IValidator<Widget>
{
public IValidationResult<Widget> Validate(Widget entity)
{
return new ValidationResult<Widget>() { IsValid = true };
}
}
public class ValidationService
{
private readonly Dictionary<Type, IValidator> validators;
public ValidationService(Dictionary<Type, IValidator> validators)
{
this.validators = validators;
}
public IValidationResult<T> Validate<T>(T validatingObject)
{
var validator = validators[validatingObject.GetType()];
if (validator is IValidator<T> typedValidator)
{
return typedValidator.Validate(validatingObject);
}
else throw new UnknownValidationType($"No known validator for type of {validatingObject.GetType()}");
}
}
public class ServiceUser
{
private readonly ValidationService validationService;
public ServiceUser(ValidationService validationService)
{
this.validationService = validationService;
}
public void DemonstrateProblem()
{
Widget widget = new Widget() { UniqueIdentifier = Guid.NewGuid() };
Entity entity = new Entity() { Id = 1, SomeProperty = "You know" };
List<object> ObjectsToBeValidated = new List<object>() { widget, entity };
foreach(var t in ObjectsToBeValidated)
{
validationService.Validate(t);//The Generic type of T is Object because that is the type of the List.
//How to get to be the concrete type of Widget and Entity?
}
}
}
public class UnknownValidationType : Exception {
public UnknownValidationType(string message) : base(message)
{
}
}
}

Related

C# how to get Generic type properties

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

Downcasting a List<AbstractClass> object to what the object actually is

I have a ParentClass. Two classes are inherit from it, FirstChildClass and SecondChildClass. A class MultipleValueTypes contains a Dictionary and a method that adds values to it. My intention is to be able to pass values of different classes, which inherit from the same abstract class to the value parameter of the Dictionary. Therefore, I initialize the dictionary with the value List<ParentClass> so that I would be able to add objects made with the child classes to the Dictionary. I can do this, but I cannot access them, therefore in the abstract class I create a way to tell them apart, a virtual method that both the children classes override to return their own class type.
I test the values they return against the enum itself and based on whether the condition is fulfilled, the object would be casted as what it is instead of a List<ParentClass>. Is this the wrong approach? Is this impossible?
I think it should work, because in my thinking the FirstObject and SecondObject are still objects of their respective classes, so casting should work and I should be able to access the overridden method.
What doesn't work: I cannot access the method that returns what type of class it is, because it only gets methods from the List<ParentClass>.
What I've tried so far: searching for a way to access the method, but I did not find any.
What I still need help with: everything mentioned above.
public abstract class ParentClass
{
public string Name { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
}
public class FirstChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public FirstChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the FirstChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public SecondChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the SecondChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public Dictionary<string, List<ParentClass>> ADictionary = new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if (!ADictionary.ContainsKey(Name))
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
class Program
{
static void Main(string[] args)
{
FirstChildClass FirstObject = new FirstChildClass("FirstObject");
SecondChildClass SecondObject = new SecondChildClass("SecondObject");
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if(TestDictionary.ADictionary["FirstObject"].TypeOfClass() == ParentClass.ChildClasses.FirstChildClass) ///List<ParentClass>' does not contain a definition for 'TypeOfClass' and no accessible extension method 'TypeOfClass' accepting a first argument of type 'List<ParentClass>' could be found (are you missing a using directive or an assembly reference?)
{
TestDictionary.ADictionary["FirstObject"] = (FirstChildClass)TestDictionary.ADictionary["FirstObject"]; ///Cannot convert type 'System.Collections.Generic.List<Dictionary.ParentClass>' to 'Dictionary.FirstChildClass
}
}
}
You forgot to use indexer of the list value of the key of the dictionary here:
==> TestDictionary.ADictionary["FirstObject"][0]
Here is your code now refactored too:
class Program
{
static void Main(string[] args)
{
var FirstObject = new FirstChildClass("FirstObject");
var SecondObject = new SecondChildClass("SecondObject");
FirstObject.ReturnMessage();
SecondObject.ReturnMessage();
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if ( TestDictionary.ADictionary["FirstObject"][0].TypeOfClass()
== ParentClass.ChildClasses.FirstChildClass )
{
TestDictionary.ADictionary["FirstObject"][0]
= (FirstChildClass)TestDictionary.ADictionary["FirstObject"][0];
}
Console.ReadKey();
}
}
public abstract class ParentClass
{
public string Name { get; set; }
public string RandomValue { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public virtual void ReturnMessage()
{
Console.WriteLine($"This is the {this.GetType().Name} instance");
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
}
public class FirstChildClass : ParentClass
{
public FirstChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
public SecondChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public readonly Dictionary<string, List<ParentClass>> ADictionary
= new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if ( !ADictionary.ContainsKey(Name) )
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
If the intention is to cast the whole list from List<ParentClass> to List<FirstChildClass> and List<SecondChildClass>, then Linq is your friend, just use the Cast function:
List<FirstChildClass> firstChildClasses = TestDictionary.ADictionary["FirstObject"]
.Cast<FirstChildClass>().ToList();
List<SecondChildClass> secondChildClasses = TestDictionary.ADictionary["SecondObject"]
.Cast<SecondChildClass>().ToList();

Cast object from an interface to its implementation

I have the following code:
public interface BaseInterface
{
int ID { get; }
}
public interface SpecialInterface1 : BaseInterface
{
int price { get; }
}
public interface SpecialInterface1 : BaseInterface
{
int xyz { get; }
}
public class Implementation1 : SpecialInterface
{
int price { get; }
int ID { get; internal set; }
}
public class Implementation2 : SpecialInterface
{
int xyz { get; }
int ID { get; internal set; }
}
Now in a Management class I want to add the objects that implement BaseInterface into a List.
I know that I can use as or is to cast the interface to an implementation, but in my project, I have about 10 special interfaces with an implementation each so I would have to write a really big if statements.
public void Add(BaseInterface u, int id)
{
if (u is Implementation1)
{
((Implementation1)u).ID = id;
Units.Add(u);
}
if (u is Implementation2)
{
((Implementation2)u).ID = id;
Units.Add(u);
}
}
My goal is that the id is not changeable outside the implementation and I would provide only the interfaces outside my dll so none can change the id.
A solution would be to add an extra interface. This eliminates the internal setter in your implementation.
internal interface IChangeID
{
void SetID(int id);
}
public interface IBaseInterface
{
int ID { get; }
}
public class Implementation : IBaseInterface,
IChangeID
{
public void SetID(int id) { ID = id; }
public int ID { get; private set; }
}
Only the real implementations should implement IChangeID. Returning IBaseInterface or ISpecialInterface will hide the setter, because those interfaces do not inherit from IChangeID.
This would change your add into:
public void Add(BaseInterface u, int id)
{
((IChangeID)u).SetID(id);
Units.Add(u);
}
If you do want to return the concrete types, not interfaces. You could implement the given interface explicit. This will hide the set method even from the concrete implementation.
public class Implementation : IBaseInterface,
IChangeID
{
void IChangeID.SetID(int id) { ID = id; }
public int ID { get; private set; }
}
var obj = new Implementation();
obj.SetID() // This WILL NOT Compile
If you don't want to modify the interfaces and implementations, you could use C# 7's pattern matching to access the implementation type without casting. It requires 3 lines per implementation type but avoids modifying the classes:
public void Add(BaseInterface u, int id)
{
switch(u)
{
case Implementation1 u1:
u1.ID = id;
break;
case Implementation2 u1:
u1.ID = id;
break;
default :
throw new ArgumentException("Unexpected implementation!");
}
Units.Add(u);
}
The obvious disadvantage is that the code will have to be modified if a new implementation is added.
Another option is to use dynamic, losing type safety. This will fail at runtime if some implementation doesn't have a setter (eg because it was replaced by constructor initialization)
public void Add(BaseInterface u, int id)
{
dynamic x =u;
x.ID=id;
Units.Add(x);
}
While I like this answer the best,
I recommend making the ID a required parameter of all the implementation's constructors, and then to use a factory pattern to generate any instance you require. This makes any instance without the ID set throw an exception at compile time rather than runtime reducing the probability of exceptions.
Here is a simple example that gets you what you want without an additional interface. Should you choose you can combine my answer with #Iqon's answer.
public interface IInterface
{
int ID { get; }
}
internal class InternalImplementation: IInterface {
public InternalImplementation(int ID) { this.ID = ID; }
public int ID { get; set; }
}
public class MyImplementationFactoryService {
public IInterface Create() {
int id = 1 // Or however you get your ID, possibly from a DB query?
return new InternalImplementation(id);
}
public IInterface Create(type|enum createtype) {
// return type based on typeof or enum
}
}
In case you want to use reflection to set property, code below may help
public interface IBaseInterface
{
int ID { get; }
}
public class Impl1 : IBaseInterface
{
public int ID { get; internal set; }
public int Price {get; set;}
}
public class Impl2 : IBaseInterface
{
public int ID { get { return 0;} }
public int Subscription {get; set;}
}
public class Program
{
public static void Main(string[] args)
{
IBaseInterface obj1 = new Impl1();
SetProperty(obj1, "ID", 100);
Console.WriteLine("Object1 Id is {0}", obj1.ID);
IBaseInterface obj2 = new Impl2();
SetProperty(obj2, "ID", 500);
Console.WriteLine("Object2 Id is {0}", obj2.ID);
}
private static void SetProperty(IBaseInterface obj, string propertyName, object id){
if(obj.GetType().GetProperty(propertyName).CanWrite) {
obj.GetType().GetProperty(propertyName).SetValue(obj, id);
Console.WriteLine("CanWrite property '{0}' : {1}" , propertyName, obj.GetType().GetProperty(propertyName).CanWrite);
}
}
}
Output
CanWrite property 'ID' : True
Object1 Id is 100
Object2 Id is 0

Access const with generics C#

I have the following base class:
public class Base
{
public string LogicalName { get; set; }
public int NumberOfChars { get; set; }
public Base()
{
}
public Base(string logicalName, int numberOfChars)
{
LogicalName = logicalName;
NumberOfChars = numberOfChars;
}
}
and the following derived classes:
public class Derived1 : Base
{
public const string EntityLogicalName = "Name1";
public const int EntityNumberOfChars = 30;
public Derived1() : base(EntityLogicalName, EntityNumberOfChars)
{
}
}
public class Derived2 : Base
{
public const string EntityLogicalName = "Name2";
public const int EntityNumberOfChars = 50;
public Derived2()
: base(EntityLogicalName, EntityNumberOfChars)
{
}
}
and I also have this function that is provided by a service:
public IEnumerable<T> GetEntities<T>(string entityName, int numberOfChars) where T : Base
{
//Some code to get the entities
}
My problem is how can I call this function generically? I want to call it with something that looks like this:
public void TestEntities<T>() where T : Base
{
var entities = GetEntities<T>(T.EntityLogicalName, T.EntityNumberOfChars);
//some other code to test the entities
}
This of course doesn't work because at this point T is not known. How can I accomplish something similar to this? EntityLogicalName and EntityNumberOfChars are characteristics that all Base derived classes have and they never change for each derived class. Can I get them from the Base class without instantiating objects or some other way that I am not seeing?
Replace constants with getter abstract properties
public abstract class Base
{
public abstract string LogicalName { get; }
public abstract int NumberOfChars { get; }
public Base()
{
}
}
public class Derived1 : Base
{
public string LogicalName { get { return "Name1"; } }
public int NumberOfChars { get { return 30; } }
public Derived1() : base()
{
}
}
Also, you will be able to put some logic into overriden getter, e.g. :
...
public string LogicalName { get { return this.EntityMap.Name; } }
...
UPDATE: The fact that you do not want to instantiate object from class but want to be able to get that string in a strongly typed manner can be handled in one more way. It is totally separate from answer above ( Since you can't override static props in c#). Consider the following code. We are adding one more class here, but LocatorInner can be a member of BaseClass. We are using this approach a lot in several existing apps.:
public class Locator
{
public static class LocatorInner<T> where T : BaseClass
{
public static string Name { get; set; }
}
public static string GetName<T>() where T : BaseClass
{
return LocatorInner<T>.Name;
}
public static void SetName<T>(string name) where T : BaseClass
{
LocatorInner<T>.Name = name;
}
}
public class BaseClass
{
}
public class DerivedClass: BaseClass
{
static DerivedClass()
{
Locator.LocatorInner<DerivedClass>.Name = "me";
}
}
public class TestClass<T> where T : BaseClass
{
public void Method()
{
var name = Locator.GetName<T>();
}
}
IMHO, I believe using constants here is a bad design decision.
You can either solve the issue using #vittore approach, but for me it sounds like you should use meta-programming with attributes if you're looking to get data from the T generic argument
For example, what about:
public class LogicalNameAttribute : Attribute
{
public LogicalNameAttribute(string name)
{
Name = name;
}
public string Name { get; private set; }
}
public class NumberOfCharsAttribute : Attribute
{
public NumberOfCharsAttribute (int number)
{
Number = number;
}
public string Number { get; private set; }
}
[LogicalName("Name1"), NumberOfChars(30)]
public class Derived1 : Base
{
public Derived1() : base()
{
}
}
Now your service method can extract attribute metadata as follows:
public void TestEntities<T>() where T : Base
{
LogicalNameAttribute logicalNameAttr = typeof(T).GetCustomAttribute<LogicalNameAttribute>();
NumberOfCharsAttribute numberOfCharsAttr = typeof(T).GetCustomAttribute<NumberOfCharsAttribute >();
Contract.Assert(logicalNameAttr != null);
Contract.Assert(numberOfCharsAttr != null);
string logicalName = logicalNameAttr.Name;
int numberOfChars = numberOfCharsAttr.Number;
// Other stuff
}
There's a performance penalty because you need to use reflection to get attributes applied to T, but you gain the flexibility of not forcing derived classes to provide this static info.
As #vittore mentioned, move the properties to base,pass the hard coded values from derived and in creation use just defautl(T)
public IEnumerable<T> GetEntities<T>(string entityName, int numberOfChars) where T : Base
{
yield return default(T); //Is its always class use new constraint and return new T();
}

Generic type constraint and variance

I am building a simple type mapper similar to AutoMapper but with a more dynamic behaviour. The caller can decide to filter RecordStatus == RecordStatus.Deleted records when mapping from entity framework models.
Abstract mappers:
public interface IMapper<in TIn, out TOut>
{
TOut Map(TIn input);
}
public interface IRecordStatusFilterable
{
string RecordStatus { get; }
}
public abstract class RecordStatusFilterableMapperBase<TIn, TOut> : IMapper<TIn, TOut>
{
private readonly bool _filterDeletedRecords;
protected RecordStatusFilterableMapperBase(bool filterDeletedRecords)
{
_filterDeletedRecords = filterDeletedRecords;
}
protected bool FilterDeletedRecords
{
get { return _filterDeletedRecords; }
}
public abstract TOut Map(TIn input);
}
public class MultiLookupValuesMapper : RecordStatusFilterableMapperBase<IEnumerable<Lookup>, string>
{
private static readonly Func<Lookup, bool> _predicate =
filterable => filterable.RecordStatus == RecordStatus.Active;
protected MultiLookupValuesMapper(bool filterDeletedRecords) : base(filterDeletedRecords)
{
}
public override string Map(IEnumerable<Lookup> input)
{
var inputList = input as IList<Lookup> ?? input.ToList();
if (!inputList.Any())
{
return string.Empty;
}
if (FilterDeletedRecords)
{
inputList = (IList<Lookup>)inputList.Where(_predicate);
}
return string.Join(", ", inputList.Select(l => l.Value));
}
}
Concrete Mappers:
public class FooMapper<TRecordStatusFilterable> : RecordStatusFilterableMapperBase<Foo, FooViewModel>
where TRecordStatusFilterable : class, IRecordStatusFilterable
{
private readonly IMapper<IEnumerable<TRecordStatusFilterable>, string> _multiLookupValueMapper;
public FooMapper(IMapper<IEnumerable<TRecordStatusFilterable>, string> multiLookupValueMapper,
bool filterDeletedRecords) : base(filterDeletedRecords)
{
_multiLookupValueMapper = multiLookupValueMapper;
}
public override FooViewModel Map(Foo input)
{
return new FooViewModel
{
// Error here
BarLookupValues = _multiLookupValueMapper.Map(input.Lookups)
};
}
}
Entity Framework model:
public class Foo
{
public ICollection<Lookup> Lookups { get; set; }
}
public class Lookup : IRecordStatusFilterable
{
public string Value { get; set; }
public string RecordStatus { get; set; }
}
ViewModels:
public class FooViewModel
{
// ICollection<Lookup> => string
public string BarLookupValues { get; set; }
}
I got a compile error:
Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable<Lookup>' to 'System.Collections.Generic.IEnumerable<TRecordStatusFilterable>'
But my Lookup class does fulfill the generic type parameter constraint as it implements IRecordStatusFilterable. Can anyone shed some light on this?
Actually a lot of the code is irrelevant to the actual problem. Here is a simpler version that, hopefully, illustrates it better:
class MyList<T>
where T : class, IConvertible
{
private List<T> list = new List<T>();
public void Add(string s)
{
list.Add(s); // error
}
}
Yes T is constrained, and string fits the constraints, but that doesn't mean you can go and add string to a List of arbitrary T's. That wouldn't type safe.
If I defined
class Bar : IConvertible { /* left out IConvertible impl */ }
and made a var bars = new MyList<Bar>() it is obvious that adding a string to bars is a problem for that code in the generic class.
You've just got a more complex version of this and I'm not 100% sure what exactly you are trying to express. Perhaps the class FooMapper shouldn't be generic at all and should just take an instance of IMapper<IEnumerable<Lookup>, string>.

Categories