I have the following interface:
public interface IReport
{
int ReportId {get; set;}
}
I have an entity that has identity column property:
public int PaymentReportId {get; set;}
I need the PaymentReport to implement IReport
Inside my PaymentReport.cs I did:
public int PaymentReportId {get; set;}
public int ReportId {
get => PaymentReportId;
set {} //no need to ever set this;
}
Otherwise the compiler was complaining about no setter implemented.
Is there a cleaner way to do this?
If you try to adhere to SOLID there is principle called interface segregation.
The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use.
With your approach the principle is obviously violated as class PaymentReport does have property setter which is essentially not needed.
Consider to split the IReport to IReportRead and IReportWrite and implement only what is necessary.
public interface IReportRead
{
int ReportId { get; }
}
public interface IReportWrite
{
int ReportId { set; }
}
public class PaymentReport : IReportRead {//...}
That way you have clear abstraction and you are not polluting the implementation.
I removed, the set from the ReportId of IReport and then implemented in the class.
public interface IReport
{
int ReportId { get; }
}
public class PaymentReport : IReport
{
public int PaymentReportId { get; set; }
public int ReportId
{
get => PaymentReportId;
}
}
As others said, the cleanest thing would be to change the interface or split into
several interfaces. Here is an example of splitting interface into two and use them in both the get scenario and the get, set scenario:
interface IFooGet
{
int Id { get; }
}
interface IFooSet
{
int Id { set; }
}
public class FooGet : IFooGet
{
public int Id { get; }
}
public class FooGetSet : IFooGet, IFooSet
{
public int Id { get; set; }
}
If that is not possible (maybe you don't own the code for the interface?) you might throw an exception if someone tries to call the property.
class PaymentReport : IReport
{
public int PaymentReportId {get; set;}
public int ReportId {
get => PaymentReportId;
set => throw new NotSupportedException();
}
}
Just having a empty body in the set may sometime lead to error hiding https://en.wikipedia.org/wiki/Error_hiding if some code in the future tries to call setter and makes the assumption that the setter actually does something meaningful
Related
I have a base class for all the ENTITIES of my project which is inheriting from below model :
public class BaseModel
{
public int Id { get; set; }
public int CreatedDate { get; set; }
public override string ToString();
}
Now I have 1 another functionality which is common for so many modules and I want to keep BaseModel for that functionality and want it to be inherited from it.
Public class BaseNotice
{
// Common info related to notice which is use to send notice to employees in different scenarios
}
Now our every model is suppose to inherit from BaseModel so inheriting from BaseNotice will be multiple inheritance.
Now I cannot like below :
Public class BaseNotice : BaseModel
{
// Common info related to notice which is use to send notice to employees in different scenarios
}
Because I would like to control functionality related to Notice from BaseNotice model and for notice I would like to keep BaseNotice as base model.
But I am not getting how to avoid multiple inheritance here and so what would be the proper way to design this?
There is No need to Multiple Inheritance. you can do that in this way:
public class BaseModel
{
public int Id { get; set; }
public int CreatedDate { get; set; }
public override string ToString();
}
public interface IBaseNotice
{
// Base Notices Contracts should be placed here
}
Public class BaseNotice: IBaseNotice
{
// Common info related to notice which is use to send notice to employees in different scenarios
}
public class ModelX:BaseModel
{
public IBaseNotice Notice { get ; set; }
public ModelX(IBaseNotice baseNotice)
{
Notice = baseNotice;
}
}
Or you can use Second Generation of your BaseModel:
public class BaseModeNoticable:BaseModel
{
public IBaseNotice Notice { get ; set; }
public BaseModeNoticable(IBaseNotice baseNotice)
{
Notice = baseNotice;
}
}
I'm looking for a class structure or design pattern to implement a base class that has a list of "base items", where several derived classes have the same list but that list is of derived "base items".
Here's a vastly stripped down example (ignore the accessibility of properties, they wouldn't actually all have public setters and default constructors):
public class BaseTransaction {
public List<BaseTransactionItem> Items { get; set; }
public void AddItem(string description, int quantity, decimal price)
{
// Add a new BaseTransactionItem to Items
}
}
public class BaseTransactionItem {
public string Description { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
public class OrderTransaction : BaseTransaction {
public List<OrderTransactionItem> Items { get; set; }
public int Deposit { get; set; }
public void SetDeposit(int depositAmount)
{
// Do some stuff to set the deposit.
}
}
public class OrderTransactionItem : BaseTransactionItem
{
public int QuantityFulfilled { get; set; }
}
public class RetailTransaction : BaseTransaction {
public List<RetailTransactionItem> Items { get; set; }
public List<Tender> Tenders { get; set; }
public void AddTender(Tender tender)
{
// Add a tender to the RetailTransaction
}
public decimal TotalTax
{
get { return Items.Sum(i => i.Tax); }
}
}
public class RetailTransactionItem : BaseTransactionItem
{
public decimal Tax { get; set; }
}
The way I need to work with these classes is that you start with a BaseTransaction and add some items to it, and then it can become either an OrderTransaction or a RetailTransaction. These both share most of their logic and properties with a BaseTransaction but have specific extra fields and methods, as well as the List<BaseTransactionItem> becoming a List<OrderTransactionItem> or a List<RetailTransactionItem> respectively.
Further more, after a BaseTransaction is "promoted" to a RetailTransaction, it may be "demoted" back to a BaseTransaction and then "promoted" to an OrderTransaction (but never from a RetailTransaction to an OrderTransaction in this case).
I've tried several approaches to this, with generics, the Decorator pattern (which doesn't seem appropriate), TypeConverters, and yet nothing seems to fit. The only possible solution I've thought of that works is having the RetailTransaction class have a constructor that takes a BaseTransaction and copying over all the properties and converting the list using .Cast<RetailTransactionItem> but this will make maintaining the derived classes pretty difficult.
If it wasn't for the list type needing to change this would be a simple case of using inheritance. I'm completely open to alternative approaches such as those favouring composition over inheritance but since the RetailTransaction and OrderTransaction classes truely are more specific versions of BaseTransaction, inheritance seems to fit - at least in my mind.
I'm just wondering if there is a way to Map Properties from a class to an interface with out changing their names.
Say you imported some entities from a Database
public partial class Post
{
public int PostId {get; set;}
}
public partial class Book
{
public int BookId {get; set;}
}
and an interface:
public interface IHasID
{
int Id {get; set;}
}
is there a way to inherit from this interface and just map the Properties using attributes like:
public partial class Post : IHasID
{
[MetadataTypeAttribute(typeof(IHasID.Id))]
public int PostId;
}
I just want a simple way to do this without wrapping all of the code or changing the database. Is there a way to wrap the parital class to point its property as an interface property?
You could create an ID property which gets and sets your object's appropriate ID, like this:
public partial class Post : IHasID
{
[NotMapped]
public int Id
{
get { return PostId; }
set { PostId = value; }
}
public int PostId { get; set; }
...
You would of course do the same thing for Book.
I'm not sure if it's worth pointing out just for the sake of knowledge that, if it were vb.net, you could do it just like this:
Partial Public Class Post
Implements IHasID
Public Property PostId As Integer Implements IHasID.Id
End Class
I am using EF code first to generate my db and I do need concrete property for ICollection of EF entity models. I am writing a data access layer ( Using generic classes) however hit the following road block with using interfaces in my generic class as shown below.
public interface ITestClassProp
{
int Value { get; set; }
}
public class TestClassProp : ITestClassProp
{
public int Value { get; set; }
}
public interface ITestClass
{
ICollection<ITestClassProp> TestProp { get; set; }
}
public class TestClass : ITestClass
{
// works
//public ICollection<ITestClassProp> TestProp { get; set; }
// does not work
public ICollection<TestClassProp> TestProp { get; set; }
}
Am I totally mis using the interfaces? why cant I use TestClassProp instead of ITestClassProp?
Thanks
When you implement an interface, you have to implement the methods/properties of that interface with the same signature. Since the interface declares ICollection<ITestClassProp> TestProp { get; set; } then your TestClass must also declare ICollection<TestClassProp> TestProp { get; set; }.
The reason this is necessary is that other classes that know about the interface but not the concrete class are expecting the property to be ICollection<ITestClassProp> and not ICollection<TestClassProp>.
As you've currently written your code, you are not satisfying the requirement you've imposed via your ITestClass interface, which is to have a property of ICollection<ITestProp>.
One way around this is to actually make ITestClass generic, but provide a generic constraint of ITestClassProp
public interface ITestClassProp
{
int Value { get; set; }
}
public class TestClassProp : ITestClassProp
{
public int Value { get; set; }
}
public interface ITestClass<T> where T : ITestClassProp
{
ICollection<T> TestProp { get; set; }
}
public class TestClass : ITestClass<TestClassProp>
{
public ICollection<TestClassProp> TestProp { get; set; }
}
This allows you to provide any concrete type that implements ITestProp to your ICollection.
Simply, the interface declares a property of type ICollection, but you implement it as ICollection, which has a totally different signature.
You might want to read up on covariance and contravariance also.
Having the two class/inteface below:
[Schema("dbo")]
[Alias("Team")]
public class Team : IHasId<int>
{
[Alias("TeamId"), AutoIncrement]
public int Id { get; set;}
[Required]
public string TeamName { get; set;}
[Required]
public DateTime CreatedOn { get; set;}
[Required]
public int DivisionId { get; set; }
[Required]
public bool IsActive { get; set; }
}
public interface ITotal
{
DateTime Date { get; set; }
Team Team { get; set; }
Account Account { get; set; }
double Total { get; set; }
}
public class Total: ITotal
{
public DateTime Date {get; set;}
public Team Team {get; set;}
public Account {get; set;}
public double Total {get; set;}
}
I am trying to create a default method to return a sum of total by Team id, I am not very familiar using interfaces, so I am not sure if what I did was the best solution, also should I use something like ITotalCollection instead of List ?
public class QueryTotalCollection: List<Total>
{
public List<Total> GetTotalByTeam()
{
// todo: I need to return here the same object. However,
// grouping by Team and the Sum of .Total (in this case the
// property "Account" will return null as I am grouping by Team.
// for instance: select Date, Team, null as Account, sum(Total)
// group by Date, Team
// return this.GroupBy(x => x.Team.Id)...
}
}
The method above is not working, how can I do this? I want to return a
sum of ITotal.Total grouped by Team.Id
There is basic misuse of interfaces and what you think it does. First of all if you want to create a class that does return a sum of total, then do just that. You need no interfaces for that.
But if you have multiple classes (at least two) that will implement ITotal interface, then I would recommend use helper method, as it is what you need (you need helper method right?). Info about extending class. Sample code:
public static class TeamSelectHeleper
{
public static double GetTotalByTeam(this List<ITotal> myList)
{
// TODO Sum wont work this way - fix it
//return myList.GroupBy(x => x.Team.Id).Sum(s => s.Total);
// If you need just a sum, then just sum it.
// but if you need group results,
// then you can just return on number when there is a list
return myList.Sum(s => s.Total);
}
}
You can then apply this method to any list containing ITotal.
And group by doesn't work the way you think it does. Use stack answer or MSDN
You need to properly implement that ITotal interface with one of your classes which will include all the declared methods of that interface. Something like this :
public class QueryTotalCollection: ITotal
{
public double Total()
{
//your actual method body code.
}
}
Also, you might want to read some basic stuff about Interfaces and how they are used and implemented. That should help you through this.
Hope this helps.