I have a problem while adding a new class in my existing structure. I am going to explain my problem as much clear as i can
public interface Imust
{
string Name { get; set; }
string File { get; set; }
string RowKey { get; set; }
string Time { get; set; }
string PartitionKey { get; set; }
}
public class TA : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class TB : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class TC : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class _Table <T> : _Account where T : Imust
{
}
Here the above 3 classes are implemented as Tables and its properties as its columns in my project. Imust interface is implemented in each class because in generic class i put an interface constraint. TableServiceEntity class contains the implementation for RowKey and PartitionKey.And this class is also inherited in all 3 entities.
Problem : Now i have to add a new table in my application. So for this i have to add a new class here which is
public class TD : TableServiceEntity
{
}
I do not want this class to implement the Imust interface because it does not contain these columns. But i have to pass it as a parameter in generic class _Table.Because this new class has different columns but it perform same function which other 3 entities does. Now how will i add this new class while maintaining my existing structur ?
Please suggest me any better solution for this problem ?
EDIT
Yes i can put a constraint TableServiceEntity as a base class. But in generic class _Table there are few function which operate on File property like
public T AccessEntity(string Id = "0", string File = "0")
{
return (from e in ServiceContext.CreateQuery<T>(TableName)
where e.RowKey == Id || e.File == File
select e).FirstOrDefault();
}
If i removed this interface constraint then it shows an error that T does not have a defination for File.
I'd do this... the interface has no sense in your declaration as the more generic type for table is TableServiceEntity
public class _Table <T> : _Account where T : TableServiceEntity
{
}
Split the interface in two:
public interface Ibase
string RowKey { get; set; }
string PartitionKey { get; set; }
}
public interface Imust : Ibase
{
string Name { get; set; }
string File { get; set; }
string Time { get; set; }
}
public class TA : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class TB : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class TC : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class _BaseTable <T> : _Account where T : Ibase
{
}
public class _Table <T> : _BaseTable<T> where T : Imust
{
}
And implement common functionality in _BaseTable and this specific to Time, Name and File in _Table.
It's even more intuitive after and edit you have made to your question. Thos methods in _BaseTable that rely on File, Name or Time can be marked abstract and overriden in _Table.
Updated to reflect posters additional info:
You need to specify a new Interface:
public interface IMust2 {
public string File {get;set;}
public string Rowkey {get;set;
}
Modify IMust to inherit from IMust2
public interface IMust : IMust2
{
public string Name {get;set;}
public string Time {get;set;}
public string PartitoinKey {get;set;}
}
Why not just have _Table be of <TableServiceEntity> type? Obviously, you are breaking your interface, so you can't keep using it as the generic as not every class will be of that interface?
You have 3 classes (TA, TB and TC) that are exactly the same. Why don't you have a single class, though?
For behavior (that is, methods), use a interface. For structure (that is, properties), use inheritance (like at TableServiceEntity).
Make TD inherit from the base class but do not implement the interface.
Change the restriction at _Table to be where T : TableServiceEntity
Regards
Related
I have an Generic Abstract Class with some properties like Id, Name, Status, this class inherits several catalogs.
My question is whether it is possible to create a method with a restriction for the catalogs that implement the Abstract Class.
I give some examples so that they understand what I want to do:
public abstract class AbsCatalog<T>
{
public T Id { get; set; }
public string Name { get; set; }
public bool Status { get; set; }
}
These are the classes that implement the abstract class
public class Agent : AbsCatalog<string>
{
public string Office { get; set; }
public Estado Estado { get; set; }
}
public class Models : AbsCatalog<int>
{
public int Year { get; set; }
public string Description { get; set; }
}
The method I want to implement is the following:
List<Agent> Agents = service.GetAgents();
string AgentsDescription = GetDescription<Agent>(Agents);
List<Model> Models = service.GetModels();
string ModelsDescription = GetDescription<Model>(Models);
private string GetDescription<T>(List<T> list) where T : AbsCatalog<T>
{
string description = string.Empty;
if (list.Exists(x => x.Id.ToString() == "0"))
description = "";
else
description = string.Join(", ", list.Where(x => x.Status).Select(x => x.Name).ToArray());
return description;
}
I think the only way is to use two generic type parameters here, for example:
private string GetDescription<T, U>(List<T> list) where T : AbsCatalog<U>
{
//snip
}
And then call it like this:
string AgentsDescription = GetDescription<Agent, string>(Agents);
Let's say I have nested generic data classes similar to the following:
public class BaseRecordList<TRecord, TUserInfo>
where TRecord : BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual IList<TRecord> Records { get; set; }
public virtual int Limit { get; set; }
}
public class BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
public class BaseUserInfo
{
public virtual string Name { get; set; }
public virtual int Age { get; set; }
}
With 2 concrete versions like so:
// Project 1: Requires some extra properties
public class Project1RecordList : BaseRecordList<Project1Record, Project1UserInfo> {}
public class Project1Record : BaseRecord<Project1UserInfo>
{
public Guid Version { get; set; }
}
public class Project1UserInfo : BaseUserInfo
{
public string FavouriteFood { get; set; }
}
and
// Project 2: Some properties need alternate names for JSON serialization
public class Project2RecordList : BaseRecordList<Project2Record, Project2UserInfo>
{
[JsonProperty("allRecords")]
public override IList<Project2Record> Records { get; set; }
}
public class Project2Record : BaseRecord<Project2UserInfo> {}
public class Project2UserInfo : BaseUserInfo
{
[JsonProperty("username")]
public override string Name { get; set; }
}
I'm then happy to have 2 repositories that return Project1RecordList and Project2RecordList respectively, but at some point in my code I find myself needing to be able to handle both of these in one place. I figure that at this point I need to be able to treat both of these types as
BaseRecordList<BaseRecord<BaseUserInfo>, BaseUserInfo>
as this is the minimum required to meet the generic constraints, but trying to cast or use "as" throws up errors about not being able to convert.
Is there any way to do this, or even a more sane way to handle this situation without massive amounts of code duplication? If it makes any difference this is for a web app and there are already a large number of data classes, many of which use these nested generics.
What you are talking about is called covariance and MSDN has a great article on this here: https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx
First, create a new interface:
interface IBaseRecord<out TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecord inherit from the new interface:
public class BaseRecord<TUserInfo> : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
If done right, this should compile:
IBaseRecord<BaseUserInfo> project1 = new Project1Record();
IBaseRecord<BaseUserInfo> project2 = new Project2Record();
To expand this to the BaseRecordList, create IBaseRecordList:
interface IBaseRecordList<out TRecord, out TUserInfo>
where TRecord : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecordList inherit from that:
public class BaseRecordList<TRecord, TUserInfo> : IBaseRecordList<TRecord, TUserInfo>
And then use as such:
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project1 = new Project1RecordList();
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project2 = new Project2RecordList();
Once you have that setup, just add whatever properties or functions you need to use generically to the interfaces.
I write two public classes (test1, test2) with two fields, e. g. 'Name' and 'Surname'.
Then, I would like to fill data from a database to this objects.
My first try was:
public List<T> FillFromDB<T>()
{
IQueryable<T> query =
from tbl in _table
select new T {Name=tbl.name, Surname=tbl.surname}
}
But T don't know the fields. What could I do? Thanks for your help.
You can create a common interface (or class) from which Test1 and Test2 would inherit from and then specify the necessary constraints on the type parameter of FillFromDb.
public interface IHasName
{
public string Name { get; set; }
public string Surname { get; set; }
}
public class Test1 : IHasName
{
public string Name { get; set; }
public string Surname { get; set; }
}
public class Test2 : IHasName
{
public string Name { get; set; }
public string Surname { get; set; }
}
public List<T> FillFromDB<T>()
where T : new(), IHasName
{
IQueryable<T> query =
from tbl in _table
select new T {Name=tbl.name, Surname=tbl.surname}
}
So, I have 3 fields/properties. Say, they are, paramA, paramB, paramC. And I’ve three classes as Class A, Class B, Class C.
Requirement is to use:
• paramA, paramB in Class A
• paramA, paramC in Class B
• paramB, paramC in Class D
Is there any way to declare all these 3 properties in a common place and derive in the A,B,C classes as per the requirement....?
UPDATE
Please find some more details of the requirement:
The real requirement is:
There is a table ‘Que Table’ in database which is having following fields
• bool IsQb
• bool IsOverride
• string Identifier
• string userlogin
• FolderName
Following model classes are using for create/update/delete data in ‘Que Table’.
• CreateQue class
• UpdateQue class
• DeleteQue class
CreateQue class only requires the properties:IsQb, IsOverride,UserLogin, FolderName
UpdateQue class only requires the properties: IsQb, IsOverride, Identifier, UserLogin, FolderName
And DeleteQue class only requires: Identifier property.
The code for the model classes are:
public class CreateQue
{
public bool IsQb { get; set; }
public bool IsOverride { get; set; }
public string userlogin { get; set; }
public string FolderName { get; set; }
}
public class UpdateQue
{
public bool IsQb { get; set; }
public bool IsOverride { get; set; }
public string Identifier { get; set; }
public string userlogin { get; set; }
public string FolderName { get; set; }
}
public class DeleteQue
{
public string userlogin { get; set; }
public string Identifier { get; set; }
}
So, is there any pattern/architecture out there to declare all those properties in a single place and derive as per the requirement in those model classes....? Thanks in advance
It's a bit unclear what you need to do as we can't see your requirements. You could use interfaces:
public interface IHasPropertyA
{
string PropertyA { get; set; }
}
public interface IHasPropertyB
{
string PropertyB { get; set; }
}
public class ClassA : IHasPropertyA, IHasPropertyB
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
}
I have an application that has a concept of a Venue, a place where events happen. A Venue has many VenueParts. So, it looks like this:
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<VenuePart> VenueParts { get; set; }
}
A Venue can be a GolfCourseVenue, which is a Venue that has a Slope and a specific kind of VenuePart called a HoleVenuePart:
public class GolfCourseVenue : Venue
{
public string Slope { get; set; }
public virtual ICollection<HoleVenuePart> Holes { get; set; }
}
In the future, there may also be other kinds of Venues that all inherit from Venue. They might add their own fields, and will always have VenueParts of their own specific type.
Here are the VenuePart classes:
public abstract class VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public override string NameDescriptor { get { return "Hole"; } }
public int Yardage { get; set; }
}
My declarations above seem wrong, because now I have a GolfCourseVenue with two collections, when really it should just have the one. I can't override it, because the type is different, right? When I run reports, I would like to refer to the classes generically, where I just spit out Venues and VenueParts. But, when I render forms and such, I would like to be specific.
I have a lot of relationships like this and am wondering what I am doing wrong. For example, I have an Order that has OrderItems, but also specific kinds of Orders that have specific kinds of OrderItems.
Update: I should note that these classes are Entity Framework Code-First entities. I was hoping this wouldn't matter, but I guess it might. I need to structure the classes in a way that Code-First can properly create tables. It doesn't look like Code-First can handle generics. Sorry this implementation detail is getting in the way of an elegant solution :/
Update 2: Someone linked to a search that pointed at Covariance and Contravariance, which seemed to be a way to constrain lists within subtypes to be of a given subtype themselves. That seems really promising, but the person deleted their answer! Does anyone have any information on how I may leverage these concepts?
Update 3: Removed the navigation properties that were in child objects, because it was confusing people and not helping to describe the problem.
Here's one possible option using generics:
public abstract class VenuePart
{
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public string NameDescriptor { get{return "I'm a hole venue"; } }
}
public class Venue<T> where T : VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<T> VenueParts { get; set; }
}
public class GolfCourseVenue : Venue<HoleVenuePart>
{
}
Here GolfCourseVenue has the collection VenueParts, which can contain HoleVenueParts or super classes HoleVenueParts. Other specializations of Venue would restrict VenueParts to containing VenueParts specific to that venue.
A second possibility is pretty much as you had it
public abstract class VenuePart
{
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public string NameDescriptor { get{return "I'm a hole venue"; } }
}
public class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<VenuePart> VenueParts { get; set; }
}
public class GolfCourseVenue : Venue
{
}
Now GolfCourseVenue has the collection VenueParts, which can contain VenueParts or super classes VenueParts. Here all specializations of Venue can contain any type of VenuePart which may or may not be appropriate.
In answer to your comment about covariance, I would propose something like this:
public abstract class VenuePart
{
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public override string NameDescriptor { get{return "I'm a hole venue"; } }
}
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public abstract ICollection<VenuePart> VenueParts { get; }
}
public class GolfCourseVenue : Venue
{
private ICollection<HoleVenuePart> _holeVenueParts;
public GolfCourseVenue(ICollection<HoleVenuePart> parts)
{
_holeVenueParts = parts;
}
public override ICollection<VenuePart> VenueParts
{
get
{
// Here we need to prevent clients adding
// new VenuePart to the VenueParts collection.
// They have to use Add(HoleVenuePart part).
// Unfortunately only interfaces are covariant not types.
return new ReadOnlyCollection<VenuePart>(
_holeVenueParts.OfType<VenuePart>().ToList());
}
}
public void Add(HoleVenuePart part) { _holeVenueParts.Add(part); }
}
I look forward to the advice of others - but my approach is to use generics in this case. With generics, your GolfCourseVenue's "parts" are strong typed!
...and as I type this everyone else is saying generics too. HOW DO YOU overstackers type so dang fast?!
Anyways, pretending I'm still first -
public class VenuePart
{
}
public class HoleVenuePart : VenuePart
{
}
public abstract class Venue<T> where T : VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<T> Parts { get; set; }
}
public class GolfCourseVenue : Venue<HoleVenuePart>
{
public string Slope { get; set; }
}
Also, as a 2nd option, you could use an interface too, so in case you didn't like the name Parts, you could call it Holes when the derived type is known to be a GolfCourse
public class VenuePart
{
}
public class HoleVenuePart : VenuePart
{
}
public interface IPartCollection<T> where T : VenuePart
{
ICollection<T> Parts { get; set; }
}
public abstract class Venue<T> : IPartCollection<T> where T : VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<T> Parts { get; set; }
}
public class GolfCourseVenue : Venue<HoleVenuePart>
{
public string Slope { get; set; }
ICollection<HoleVenuePart> IPartCollection<HoleVenuePart>.Parts { get { return base.Parts; } set { base.Parts = value; }}
public virtual ICollection<HoleVenuePart> Holes { get { return base.Parts; } set { base.Parts = value;}}
}
You can use Covariance
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual IEnumerable<VenuePart> VenueParts { get; set; }
}
public class GolfCourseVenue : Venue
{
public string Slope { get; set; }
public GolfCourseVenue()
{
List<HoleVenuePart> HoleVenueParts = new List<HoleVenuePart>();
HoleVenueParts.Add(new HoleVenuePart());
VenueParts = HoleVenueParts;
}
}
Assuming HoleVenuePart is inherited from VenuePart
If you remove "set" portions of both collections than it will make more sense: base class provides "all parts" collection, while derived classes have filtered view in addition to base class one.
Note: Depending on your needs making GolfVenue to be specialization generic of Venue<VenuePart> may not work as Venue<Type1> and Venue<Type2> will not have any good base class to work with.
Consider using interfaces instead of base classes as it would allow more flexibility in implementation.
public interface IVenue
{
public int Id { get; }
public string Name { get; }
public virtual IEnumerabe<VenuePart> VenueParts { get; }
}
public interface IGolfCourse : IVenue
{
public virtual IEnumerabe<HoleVenuePart> Holes { get; }
}
Now you can use GolfCourse:Venue from other samples but since it implements interface you can handle it in gnereic way too:
class GolfCourse:Venue<HoleVenuePart>, IGolfCourse {
public virtual IEnumerabe<VenuePart> Holes{ get
{
return VenueParts.OfType<HoleVenuePart>();
}
}
}
class OtherPlace:Venue<VenuePart>, IVenue {...}
List<IVenue> = new List<IVenue> { new GolfCourse(), new OtherPlace() };
Nothe that GolfCourse and OtherPlace don't have common parent class (except object), so without interface you can't use them interchangebly.