How to declare List variable in abstract class - c#

I am trying to write a basic abstract class where any class that extends it will have a List of some type.
The context is I call a web service, and I receive "pages" of orders, and each order has "pages" of order lines, etc.
abstract class Pagination
{
public int _offset { get; set; }
public int _total { get; set; }
public string previous { get; set; }
public string next { get; set; }
// Can I add something here that represents a list of items
// that is overridden in child classes somehow?
// public abstract List<Something?> items { get; set; }
// The purpose is for this generic "getItemCount" function or something similar
/*
public int getItemCount()
{
return items != null ? items.Count() : 0;
}
*/
}
class OrderHeader : Pagination
{
public int orderId { get; set; }
public List<OrderLine> items { get; set; }
}
class OrderLine : Pagination
{
public string sku { get; set; }
public int qty { get; set; }
public List<OrderLineDetails> items { get; set; }
}
class OrderLineDetails
{
public string serialNum { get; set; }
}

You can do that with generics
public abstract class Pagination<T>
{
public abstract List<T> Items { get; set; }
}
public class OrderHeader : Pagination<OrderLine>
{
public override List<OrderLine> Items { get; set; }
}
public class OrderLine : Pagination<OrderLineDetails>
{
public override List<OrderLineDetails> Items { get; set; }
}

You can use generics, e.g.:
abstract class Pagination<T>
{
// Other properties
public List<T> items { get; set; }
}
class OrderHeader : Pagination<OrderLine>
{
// Other properties
}
class OrderLine : Pagination<OrderLineDetails>
{
// Other properties
}
class OrderLineDetails
{
// Other properties
}

As addition to answers containing overriding I'll try to show slightly different approach which may broaden horizons. If you'll change your abstract class implementation you don't even need to override your Collection unless you need explicit implementation for get; or set; because you're specifying generic by inheritance itself
abstract class Pagination<T>
{
public virtual List<T> Items { get; set; }
}
class Tester : Pagination<string>
{
public void Test()
{
foreach (string item in this.Items)
{
// you have declared List<string> from Pagination<T>
}
}
}
Also this one may be useful for you: Generic Type in constructor
By that approach you would ended up with one base class which will provide you your generic List
abstract class Pagination2<T>
{
public string Property1 { get; set; }
public List<T> Items { get; set; }
public static Pagination2<T> GetInstance<T>()
{
Pagination2<T> instance = new Pagination2<T>()
{
Items = new List<T>()
};
return instance;
}
}

abstract class Pagination<T>
{
public int _offset { get; set; }
public int _total { get; set; }
public string previous { get; set; }
public string next { get; set; }
public List<T> items { get; set; }
public int getItemCount()
{
return items != null ? items.Count() : 0;
}
}
class OrderHeader : Pagination<OrderLine>
{
public int orderId { get; set; }
}
class OrderLine : Pagination<OrderLineDetails>
{
public string sku { get; set; }
public int qty { get; set; }
}

Related

Common interface usage in ctor for some classes

In my CollectionService class i want to be able to use either DatabaseWatchService or RemoteFilesWatchService therefore I used IWatchService<IEntity> watchService parameter which should be common for both. Nevertheless in DoIt() when i try to use either one of the class i am having following error:
Cannot implicitly convert type 'RemoteFilesWatchService' to
'IWatchService'. An explicit conversion exists (are you missing a
cast?)
How to fix that to able to use in CollectionService either one mentioned class or another.
This is the full code:
public interface IWatch
{
void Watch();
}
public interface IWatchService<TDataEntity> where TDataEntity : IEntity
{
INotificationFactory NotificationFactory { get; }
ObservableCollection<TDataEntity> MatchingEntries { get; set; }
}
public interface IDatabaseWatchService<TDataEntity> : IWatchService<TDataEntity> where TDataEntity : IDatabaseEntity
{
IDatabaseRepository<IDbManager> DatabaseRepository { get; }
}
public interface IRemoteFilesWatchService<TDataEntity> : IWatchService<TDataEntity> where TDataEntity : IFileEntity
{
List<string> ExistingRemoteFiles { get; set; }
List<RemoteLocation> RemoteLocations { get; set; }
IWinScpOperations RemoteManager { get; set; }
IRemoteFilesRepository<IDbManager, TDataEntity> RemoteFilesRepository { get; }
}
public class RemoteFilesWatchService : IRemoteFilesWatchService<IFileEntity>, IWatch
{
public INotificationFactory NotificationFactory { get; }
public ObservableCollection<IFileEntity> MatchingEntries { get; set; }
public List<string> ExistingRemoteFiles { get; set; }
public List<RemoteLocation> RemoteLocations { get; set; }
public IWinScpOperations RemoteManager { get; set; }
public IRemoteFilesRepository<IDbManager, IFileEntity> RemoteFilesRepository { get; }
public RemoteFilesWatchService(IWinScpOperations remoteOperator,
IRemoteFilesRepository<IDbManager, IFileEntity> remoteFilesRepository,
INotificationFactory notificationFactory)
{
RemoteManager = remoteOperator;
RemoteFilesRepository = remoteFilesRepository; //csv, xml or other repo could be injected
NotificationFactory = notificationFactory;
}
public void Watch()
{
}
}
public class DatabaseWatchService : IDatabaseWatchService<DatabaseQuery>, IWatch
{
public INotificationFactory NotificationFactory { get; }
public ObservableCollection<DatabaseQuery> MatchingEntries { get; set; }
public IDatabaseRepository<IDbManager> DatabaseRepository { get; }
public DatabaseWatchService(IDatabaseRepository<IDbManager> databaseRepository,
INotificationFactory notificationFactory)
{
DatabaseRepository = databaseRepository;
NotificationFactory = notificationFactory;
}
public void Watch()
{
}
}
public class CollectionService
{
private IWatchService<IEntity> _watchService;
public CollectionService(IWatchService<IEntity> watchService)
{
_watchService = watchService;
}
}
class Run
{
void DoIt()
{
IWatchService<IEntity> fileWatcherServiceCsv = new RemoteFilesWatchService(new WinScpOperations(),
new RemoteCsvFilesRepository(new DbManager(ConnectionDbType.MySql)),
new NotificationFactory());
var coll1 = new CollectionService(fileWatcherServiceCsv);
}
}
public interface IEntity
{
}
public interface IFileEntity : IEntity
{
int Id { get; set; }
string Name { get; set; }
bool IsActive { get; set; }
bool RemoveFromSource { get; set; }
string DestinationFolder { get; set; }
RemoteLocation RemoteLocation { get; set; }
}
public interface IDatabaseEntity : IEntity
{
}
public class CsvFile : IFileEntity
{
public int ColumnHeader { get; set; }
public int ColumnsCount { get; set; }
public string Separator { get; set; }
public int ValuesRowStartposition { get; set; }
public int ColumnRowPosition { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public bool RemoveFromSource { get; set; }
public string DestinationFolder { get; set; }
public RemoteLocation RemoteLocation { get; set; }
}
public class XmlFile : IFileEntity
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public bool RemoveFromSource { get; set; }
public string DestinationFolder { get; set; }
public RemoteLocation RemoteLocation { get; set; }
public string SubNode { get; set; }
public string MainNode { get; set; }
}
Rather than having IWatchService expose a concrete type, I'd suggest instead having it require reimplementation of those interfaces from ObservableCollection that you actually want the consumers to use (or move those onto another interface and have that be what MatchingEntries returns).
Here I've guessed that the consumers want the events that the observable collection raises and to be able to enumerate the collection and that's all, which means we can a) implement those interfaces and b) make the interface covariant:
public interface IWatchService<out TDataEntity> :
INotifyCollectionChanged,
INotifyPropertyChanged,
IEnumerable<TDataEntity>
where TDataEntity : IEntity
{
INotificationFactory NotificationFactory { get; }
}
Now, if the implementations choose to use an ObservableCollection and just use simple wrappers to implement those interfaces or choose to satisfy the interface in some other way has been move back into an implementation decision.

Cannot implement property using derived class

public interface IBase
{
int Id { get; set; }
}
public interface IDerivedA : IBase
{
int Name { get; set; }
int Quantity { get; set; }
}
public interface IDerivedB : IBase
{
string Name { get; set; }
IEnumerable<IDerivedA> DerivedBs { get; set; }
}
And here is an implementation for a class which will be serialized, but I'm getting compilation error when I try to use DerivedASerialize class which is a derived class from IDerivedA interface
[MessagePack.Union(0, typeof(DerivedASerialize))]
[MessagePack.Union(1, typeof(DerivedBSerialize))]
[MessagePack.MessagePackObject(true)]
public class BaseSerialize : IBase
{
public int Id { get; set; }
public bool IsNull { get;set; }
}
[MessagePack.MessagePackObject(true)]
public class DerivedASerialize : BaseSerialize, IDerivedA
{
public int Name { get; set; }
public int Quantity { get; set; }
}
[MessagePack.MessagePackObject(true)]
public class DerivedBSerialize : BaseSerialize, IDerivedB
{
public string Name { get; set; }
public IEnumerable<DerivedASerialize> DerivedBs { get; set; }
}
Is there any work around? as I can only serialize classes.
And I would like to have another class which also derive from the same interface and have different properties
Using neuec's MessagePack.
Edit: Add serialization logic to classes.
If you require two different "Name" fields you can use explicit interface implementation:
public class DerivedBSerialize : BaseSerialize, IDerivedB
{
public string Name { get; set; }
public IEnumerable<DerivedASerialize> DerivedBs { get; set; }
string IDerivedB.Name { get; set; }
IEnumerable<IDerivedA> IDerivedB.DerivedBs { get; set; }
}
If you require just a single "Name" field - you can raise it to "IBase", or create another interface -
interface INameable { string Name {get; set;} }

Mapping Service Class with two Class to DTO Class with properties

I have a service Class list with two Class inside:
public class ParentClass
{
public ChildClass A { get; set; }
public ChildClass2 B { get; set; }
}
public class ChildClass
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ChildClass2
{
public string Color { get; set; }
public string Nick { get; set; }
}
And I would want mapping with AutoMapper into list that have the same properties that Child's Class:
public class DTOClass
{
public int Id { get; set; }
public string Name { get; set; }
public string Color { get; set; }
public string Nick { get; set; }
}
It work fine:
My config:
Mapper.CreateMap<ChildClass, DTOClass>();
Mapper.CreateMap<ChildClass2, DTOClass>();
My code:
List<ParentClass> listParentClass = getListParentClass();
List<DTOClass> listDtoClass = new List<DTOClass>();
ParentClass dtoClass = new ParentClass();
foreach (var parentClass in listParentClass)
{
dtoClass = AutoMapper.Mapper.Map<ChildClass, DTOClass >(parentClass.A);
AutoMapper.Mapper.Map<ChildClass2, DTOClass >(parentClass.B, dtoClass);
listDtoClass.Add(dtoClass);
}
Would I like to remove the foreach, can I?
I searched about Mapping with Child's Class, Mapping with multiple Class to one Class, no success.
I tried configurate it with ForAllMembers, but not work:
Mapper.CreateMap<ParentClass, DTOClass>()
.ForAllMembers(op => op.MapFrom(s => Mapper.Map<ChildClass, DTOClass>(s.A)));
I'm not especialist into AutoMapper, if sameone could help me. I would appreciate.
You can do this:
public class ParentClass
{
public ChildClass A { get; set; }
public ChildClass2 B { get; set; }
}
public class ChildClass
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ChildClass2
{
public string Color { get; set; }
public string Nick { get; set; }
}
public class DTOClass
{
public int AId { get; set; }
public string AName { get; set; }
public string BColor { get; set; }
public string BNick { get; set; }
}
Your mapping:
cfg.CreateMap<ChildClass, DTOClass>();
cfg.CreateMap<ChildClass2, DTOClass>();
cfg.CreateMap<ParentClass, DTOClass>();
Your example:
List<ParentClass> listParentClass = getListParentClass();
//List<DTOClass> listDtoClass = new List<DTOClass>();
var listDtoClass = AutoMapper.Mapper.Map<List<DTOClass>>(listParentClass);

Using Generics with EF classes

I'm using EF6 with Code First and have a few tables with virtually the same schema. I would like to be able to perform queries on these tables and return the results to a common object (class) rather than creating a new one for each.
So for example, EF won't allow:
public class Product1 {
public int id { get; set; }
public string name { get; set; }
}
public DbSet<Product1> Products1 { get; set; }
public DbSet<Product1> Products2 { get; set; }
So I have to define a second POCO:
public class Product1 {
public int id { get; set; }
public string name { get; set; }
}
public class Product2 {
public int id { get; set; }
public string name { get; set; }
}
public DbSet<Product1> Products1 { get; set; }
public DbSet<Product2> Products2 { get; set; }
At least I would like to be able to treat results from these POCOs the same so that I can plug results into another class:
public class SomeClass {
public <Product1 or Product2> Product { get; set; }
}
Be able to store the result from either db table in the same object:
SomeClass someclass = new SomeClass();
someclass.Product = _context.Products1.Where(p => p.id == 1).First();
or
someclass.Product = _context.Products2.Where(p => p.id == 1).First();
int thisId = someclass.Product.id;
How do I make someclass.Product generic so that it will accept either Product1 or Product2?
You would have to make the classes inherit from an interface and then use that interface in a generic type constraint.
public interface IProduct
{
int id { get; set; }
string name { get; set; }
}
public class Product1 : IProduct
{
public int id { get; set; }
public string name { get; set; }
}
public class Product2 : IProduct
{
public int id { get; set; }
public string name { get; set; }
}
Then you could define SomeClass as follows:
public class SomeClass<TProduct> where TProduct : IProduct
{
public TProduct Product { get; set; }
}

Product Site Class Structure Suggestion

I am creating a product website which have products and product categories, I have created the following classes:
public abstract class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductCode { get; set; }
public int ProductCatagoryId { get; set; }
}
public class DryFruits : Product
{
public decimal WeightInGrams { get; set; }
public decimal RatePerGram { get; set; }
}
public class DryFruitsPacks : Product
{
public string PackName { get; set; }
public decimal PackWeight { get; set; }
public decimal PackPrice { get; set; }
}
I want a method AddProduct(), which must be present in every class derived from product and adds that product to the database.
public class Product : IAddProduct
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductCode { get; set; }
public int ProductCatagoryId { get; set; }
public virtual void Add(Product p)
{
//Save to db
};
}
public class DryFruits : Product
{
public decimal WeightInGrams { get; set; }
public decimal RatePerGram { get; set; }
public override void Add(Product p)
{
//Save to db
}
}
public interface IAddProduct
{
void Add(Product product)
}
Public class SomeClass
{
Product product = new DryFruits()
{
ProductName = "Nut";
WeightInGrams = 0.01;
}
private IAddProduct _saveIt;
_saveIt.Add(product)
}
Public class SomeOtherClass
{
Product product = new Product()
{
ProductName = "Orange";
}
private IAddProduct _saveIt;
_saveIt.Add(product)
}
I always consider abstract classes to be a poor man's version of an interface. Even with the code above it fits the purpose of the SO's requirements.
You should add an abstract class to you base Product class. and override it in your derived classes.
public abstract class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductCode { get; set; }
public int ProductCatagoryId { get; set; }
public abstract void Save();
}
public class DryFruits : Product
{
public decimal WeightInGrams { get; set; }
public decimal RatePerGram { get; set; }
public override void Save()
{
//save the product
}
}
Derived classes. When you create a derived class like DryFruits or DryFruitsPacks , you must provide an override method for all abstract methods in the abstract class. The AddProduct() method in both derived classes satisfies this requirement.
Override
Int field. An abstract class can have an instance field in it. The derived classes can access this field through the base syntax..
Int
Cannot instantiate abstract class. The important part of an abstract class is that you can never use it separately from a derived class.
public abstract class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductCode { get; set; }
public int ProductCatagoryId { get; set; }
public abstract void AddProduct(params object[] arguments);
}
Abstract methods

Categories