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>.
Related
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)
{
}
}
}
I am trying to create an interface and a concrete implementation where the Interface is a generic type and one of the methods has a generic parameter.
I want to keep the GetPagedList method parameter, resourceParams, generic so I can pass in different resourceParams objects for different implementations of the Interface.
When using the code shown below, I am getting the error;
The constraints for type parameter 'U' of method 'ShippingServicesRepository.GetPagedList(U)' must match the constraints for the type parameter 'U' of interface method IBaseRepository.GetPagedList(U). Consider using an explicit interface implementation instead
Here is my interface;
public interface IBaseRepository<T>
{
bool Save();
bool Exists(int recordId);
bool MarkForDeletion(int recordId);
PagedList<T> GetPagedList<U>(U resourceParams) where U : class;
T Get(int id);
void Add(T record);
void Update(T record);
}
And here is my implementation;
public class ShippingServicesRepository<T> : IBaseRepository<T>
{
// /--- GetPagedList is what is throwing the error
// |
public PagedList<T> GetPagedList<U> (U resourceParams) where U : ShippingServicesResourceParameters
{
try
{
var collectionBeforePaging =
_manifestContext.ShippingServices
.ApplySort(resourceParams.OrderBy, _propertyMappingService.GetPropertyMapping<ShippingServicesDto, ShippingServices>());
if (!string.IsNullOrEmpty(resourceParams.SearchQuery))
{
var searchQueryForWhereClause = resourceParams.SearchQuery.Trim().ToLowerInvariant();
collectionBeforePaging = collectionBeforePaging
.Where(a => a.ReferenceId.ToLowerInvariant().Contains(searchQueryForWhereClause));
}
collectionBeforePaging = collectionBeforePaging
.Where(d => d.DeleteFlag == resourceParams.DeleteFlag);
return (dynamic)PagedList<ShippingServices>.Create(collectionBeforePaging,
resourceParams.PageNumber,
resourceParams.PageSize);
}
catch (Exception)
{
_logger.LogError(500, "ShippingServices Filter [{FILTER}]", resourceParams);
throw;
}
}
public void Add(T record)
{
...
}
public bool Exists(int recordId)
{
...
}
public T Get(int id)
{
...
}
public bool MarkForDeletion(int recordId)
{
...
}
public bool Save()
{
...
}
public void Update(T record)
{
...
}
}
Here is my ShippingServicesResourceParameters class
public class ShippingServicesResourceParameters : BaseResourceParameters
{
public string FileName { get; set; }
}
Here is the BaseResourceParameters class inherited by ShippingServicesResourceParameters
public class BaseResourceParameters
{
private int _pageSize;
public int PageNumber { get; set; } = 1;
public int PageSize
{
get
{
return _pageSize;
}
set
{
_pageSize = (value > MaxPageSize) ? MaxPageSize : value;
if (value == 0)
{
_pageSize = 10; // set a default size
}
}
}
public int MaxPageSize { get; set; } = 20;
public bool DeleteFlag { get; set; }
public string SearchQuery { get; set; }
public string OrderBy { get; set; } = "Id";
public string Fields { get; set; }
}
It I don't add the "where U : ShippingServicesResourceParameters" to the method signature in the concrete implementation and "where U : class" in the Interface, I get a "Cannot convert from Method Group to String..." error from the first use of the resourceParams variable in the concrete implementation. (at ".ApplySort(resourceParams.OrderBy")
What am I missing here?
Let's do what you should have done in the first place and make a minimal program that demonstrates the problem:
interface I
{
void M<U>(U u) where U : class;
}
class D
{
public void O() {}
}
class C : I
{
public void M<U>(U u) where U : D
{
u.O();
}
}
This is an error because C does not implement I. It does not implement I because:
I i = new C();
i.M<Giraffe>(new Giraffe());
Now we have a giraffe passed to C.M<Giraffe>(Giraffe) but C.M<U> requires that U is D. So that's illegal.
We cannot fix it like this:
public void M<U>(U u) where U : class
{
u.O();
}
because now we could have D.O() called on a receiver of type Giraffe.
Therefore we have to fix it like this:
interface I
{
void M<U>(U u) where U : D;
}
class D
{
public void O() {}
}
class C : I
{
public void M<U>(U u) where U : D
{
u.O();
}
}
And now we're all good.
You are required to make the implementation constraints match the interface constraints, just like you're required to meet every other requirement imposed by the interface. Interfaces are contracts. You have to fulfill your end of the bargain.
I note that this is what the error message says: you have to match the constraints, and you're not doing so. Pay attention to the error messages; most of the time they tell you what is wrong.
I have multiple classes like:
public class Base { }
public class Base1: Base { public static List<Base1> LoadFromXml(string path) }
public class Base2: Base { public static List<Base2> LoadFromXml(string path) }
Then I want to have a method like this:
public List<T> PrepareBase<T>() where T: Base { return T.Load("C:\test.xml"); }
So that I don't have to make a method for every type.
But I don't know how to accomplish this or something similar.
The problem is that I can't make the LoadFromXml method known to the base class because static inheritance is not a thing. Neither is creating a seperate interface with a static method.
Is there a way to do this or am I expecting too much?
Edit:
An example of the LoadFromXml method:
public class Base1
{
public int ID { get; set; }
public string PropertyOnlyInBase1 { get; set; }
public static List<Base1> LoadFromXml(string path)
{
List<Base1> baseList = new List<Base1>();
XDocument doc = XDocument.Load(path);
foreach(var node in doc.Descendants("Base1"))
{
Base 1 base = new Base1() { ID = node.Attributes["id"] };
base.PropertyOnlyInBase1 = node.Element("PropertyOnlyInBase1");
baseList.Add(base);
}
return baseList;
}
}
So the Base classes also have some unique properties. That's why I needed the inheritance thing in the first place.
One option is to add a GenericBase:
public abstract class Base
{
}
public static class GenericBase<T>
where T : Base
{
public static List<T> LoadFromXml(string path)
{
//Load from XML
}
}
public class Base1 : Base { }
public class Base2 : Base { }
public class Test //MainForm.cs class or whatever you want
{
public void Tester() //Load event handler or whatever you want
{
List<Base1> base1List = PrepareBase<Base1>();
}
public List<T> PrepareBase<T>() where T : Base
{ return GenericBase<T>.LoadFromXml("C:\test.xml"); }
}
Edit:
As D Stanley mentioned, it's not possible; but I made some work-around that could be helpful for you:
public abstract class Base
{
public static List<T> LoadFromXml<T>(string path) where T : Base, new()
{
List<T> baseList = new List<T>();
XDocument doc = XDocument.Load(path);
foreach (var node in doc.Descendants(typeof(T).Name))
{
T t = new T();
Dictionary<string, string> d = new Dictionary<string, string>();
foreach (var item in node.Elements())
d.Add(item.Name.ToString(), item.Value);
t.Load(d);
baseList.Add(t);
}
return baseList;
}
protected internal abstract void Load(Dictionary<string, string> elements);
}
public class Base1 : Base
{
public string CustomProp1 { get; set; }
public string CustomProp2 { get; set; }
public string CustomProp3 { get; set; }
protected internal override void Load(Dictionary<string, string> elements)
{
if (elements.ContainsKey("CustomProp1"))
CustomProp1 = elements["CustomProp1"];
if (elements.ContainsKey("CustomProp2"))
CustomProp2 = elements["CustomProp2"];
if (elements.ContainsKey("CustomProp3"))
CustomProp3 = elements["CustomProp3"];
}
}
public class Base2 : Base
{
public string CustomProp1 { get; set; }
public string CustomProp2 { get; set; }
public string CustomProp3 { get; set; }
protected internal override void Load(Dictionary<string, string> elements)
{
if (elements.ContainsKey("CustomProp1"))
CustomProp1 = elements["CustomProp1"];
if (elements.ContainsKey("CustomProp2"))
CustomProp2 = elements["CustomProp2"];
if (elements.ContainsKey("CustomProp3"))
CustomProp3 = elements["CustomProp3"];
}
}
public class Test //MainForm.cs class or whatever you want
{
public void Tester() //Load event handler or whatever you want
{
List<Base1> base1List = PrepareBase<Base1>();
}
public List<T> PrepareBase<T>() where T : Base, new()
{
return Base.LoadFromXml<T>("C:\test.xml");
}
}
I think you're correct that the class that loads these from XML should be separate from the class that's being loaded. As you said, it has no real connection to the instance.
Perhaps what you need is a separate class that loads those instances for you.
public class BaseXmlLoader<TBase> where TBase : Base
{
public List<TBase> LoadFromXml(string filePath)
{
var serializer = new XmlSerializer(typeof(TBase));
// Load your file and deserialize.
}
}
The benefits aren't huge because it's not saving you that much code. But if the LoadFromXml methods are essentially the same except for the type then you're getting something out of it.
I changed my approach to the problem and solved it using the Factory pattern. I also provided each class with an instance method SetPropertiesFromXml to handle the custom properties. Unlike the previously used method, a method like that made sense as an instance method.
Factory:
public static class BaseFactory
{
public static Base GetBase(string id)
{
switch(id) { case '1': return new Base1(); ... }
}
public static T GetBaseList<T>(string xml, string tagName) where T: Base
{
List<T> list = new List<T>();
var nodes = XDocument.Load(xml).Descendants(tagName);
foreach(XElement node in nodes)
{
var base = GetBase(node.Attribute("id").Value);
base.SetPropertiesFromXml(node);
list.Add(base as T);
}
}
}
Bases
public abstract class Base
{
public virtual void SetPropertiesFromXml(XElement node)
{
//<Set Properties like: this.Property = node.Element("key");>
}
}
public class Base1
{
public override void SetPropertiesFromXml(XElement node)
{
//<Set Custom Properties for Base1>
//Call Base to add the normal properties as well
base.SetPropertiesFromXml(node);
}
}
Call
List<Base1> list = BaseFactory.GetBaseList<Base1>("test.xml", "Base1");
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();
}
This question already has answers here:
Interface with List of same interface
(2 answers)
Closed 8 years ago.
I have the following interface:
public interface IObject
{
double x { get; }
double y { get; }
Holder<IObject> Holder { get; set; }
}
and this class
public class Holder<T> where T : IObject
{
private List<T> items;
public void AddItem(T item){
items.Add(item);
item.Holder = this;
}
However the compiler doesn't like the AddItem method and on this line :
item.Holder = this;
gives me this error:
Cannot convert source type 'Holder<T>' to target type 'Holder<IObject>'
Why can't I do it and what is a good solution for this scenario?
thank you
You have to bear in mind the way Genrics works in C#, The compiler create a class of the specified type, and because of that you have the error.
To explain more, given the following example:
public class InterfaceImplementation : IObject
{
}
and then some where you do :
var genericInitialisation = new Holder<InterfaceImplementation>();
The compiler at compile time will create a class HolderInterfaceImplementation replacing all accurances of the T generic parameter.
so after compilation you will have this class:
public class HolderInterfaceImplementation
{
private ListInterfaceImplementation items;
public void AddItem(InterfaceImplementation item){
items.Add(item);
item.Holder = this;
}
And item.Holder would be HolderIObject type, so the compiler report an error about not being able to convert HolderInterfaceImplementation to HolderIObject wich is logical.
After explaining the theory the solution comes naturaly and here is an example:
public interface IObject<T> where T : IObject<T>
{
double x { get; }
double y { get; }
Holder<T> Holder { get; set; }
}
public class Holder<T> where T : IObject<T>
{
public Holder()
{
items = new List<T>();
}
private List<T> items;
public void AddItem(T item)
{
items.Add(item);
item.Holder = this;
}
}
public class Implementation : IObject<Implementation>
{
public double x
{
get { return 0; }
}
public double y
{
get { return 0; }
}
public Holder<Implementation> Holder
{
get;
set;
}
}
static void Main(string[] args)
{
var t = new Holder<Implementation>();
t.AddItem(new Implementation());
Console.ReadKey();
}
If it was possible to convert that would be a type system hole:
public class Holder<T> where T : IObject
{
public T SomeField;
}
...
var holder = new Holder<IObjectSubType2>();
Holder<IObject> dummy = holder; //assuming that this works
dummy.SomeField = new IObjectSubType1(); //violates type safety
IObjectSubType2 converted = holder.SomeField;
As you can see I was able to convert an instance of IObjectSubType1 to an IObjectSubType2.
That's why this does not type check.