All of my models in all of my applications inherit from IEntity:
public interface IEntity
{
long Id { get; set; }
dynamic RelatedItems { get; set; }
}
To prevent NullReferenceException, I always write a constructor in each model:
public class Book : IEntity
{
public Book()
{
RelatedItems = new System.Dynamic.ExpandoObject();
}
// other properties of the book
}
I need the RelatedItems because my infrastructure does many things on it.
However, this boilerplate constructor is a true pain.
When C# introduced Default Implementation I thought maybe default constructors also exist now, thus I created a constructor in my IEntity interface.
But I got this error:
IEntity.cs(7,16): error CS0526: Interfaces cannot contain instance constructors
Is there a way that I can prevent this boilerplate code?
I once tried to change it to abstract base class but it messed with EF Core and its inheritance.
As #AlanK pointed out the easiest thing would be to create an abstract class providing a boilerplate implementation of your properties including any initializers like this:
public abstract class BaseEntitiy : IEntity
{
public virtual long Id { get; set; }
public virtual dynamic RelatedItems { get; set; } = new System.Dynamic.ExpandoObject();
}
you can then inherit your Book class from BaseEntity overriding properties as needed:
public class Book : BaseEntitiy
{
// example override if you need any special getters or setters for books
public override long Id
{
get => base.Id;
set
{
if (value > 0)
{
base.Id = value;
}
}
}
}
Take a look at this code.
It's better to use generic instead of dynamic, so I added a BookRelatedItem class which you can add any further properties to.
About the EntityBase class, it's an abstraction of your entities so you don't have to initialize your RelatedItems each time.
public interface IEntity<T> where T : class
{
long Id { get; set; }
IEnumerable<T> RelatedItems { get; set; }
}
public abstract class EntityBase<T> : IEntity<T> where T : class
{
public long Id { get; set; }
public IEnumerable<T> RelatedItems { get; set; }
public EntityBase()
{
RelatedItems = new List<T>();
}
}
public class Book : EntityBase<BookRelatedItem>
{
// other properties of the book
}
public class BookRelatedItem
{
//some props
}
Related
I would like to persist a class which implements an interface and can have various subclasses. I am just trying to understand how LiteDB handles this setup.
In particular I have a code structure like so:
public interface IItem
{
string UniqueKey { get; set;
string OtherProperties { get; set; }
}
public class Item : IItem
{
public string UniqueKey { get; set; }
public string OtherProperties { get; set; }
}
public class ItemOne : Item
{
public string ItemOneProperty { get; set; }
}
public class ItemTwo : Item
{
public string ItemTwoProperty { get; set; }
}
public class Main
{
public void Init()
{
// Can this apply to all interface implementations?
BsonMapper.Global.Entity<IItem>().Id(oid => oid.UniqueKey);
// This will apply to Item but not ItemOne or ItemTwo
BsonMapper.Global.Entity<Item>().Id(oid => oid.UniqueKey);
}
}
For reasons of wanting to keep the class structure clean, I do not want to use [BsonId] on the key. This means I need to use the BsonMapper to declare the ID. However, it looks like even though the mapper defines the ID on the base interface, it does not apply to any of the concrete classes.
Ideally, I do not want to declare the ID for every subclass in BsonMapper as - aside from there being many subclasses - it would create an unwanted dependency.
Does anyone know the best approach to solve this issue?
I have a rather simple problem, but I can't find a proper solution anywhere. I would like to specify an abstract object CustomValues as property in my abstract parent class. However, the class inheriting from it should be able to use a more specific type as an object for this property CustomValues. At first I thought I would solve the problem by an interface, but unfortunately that didn't work out either. How do you do something like that, that it works?
public abstract class MyAbstract {
public abstract object CustomValues { get; set; }
}
public class MyImplementation : MyAbstract {
public override MySpecificClass CustomValues { get; set; }
}
This will throw me three errors:
Missing implementation for getter
Missing implementation for setter
Type missmatch between type object and MySpecificClass
The solution suggested in the comments would look something like this. (I'm assuming CustomValues should be a collection of something.)
public class MyClass<T>
{
public ICollection<T> CustomValues { get; set; }
}
Or to ensure CustomValues itself cannot be reassigned, but can be accessed and added to:
public class MyClass<T>
{
public ICollection<T> CustomValues { get; } = new List<T>();
}
I think your original thought that use an interface (+ generic) was at the correct direction. In general you might want to add type constraints as well.
public interface ICustomValues {
....
}
public class MySpecificClass : ICustomValues {
....
}
public abstract class MyAbstract<T> where T : ICustomValues {
public abstract T CustomValues {
get;
set;
}
}
public class MyImplementation: MyAbstract<MySpecificClass> {
public override MySpecificClass CustomValues { get; set; }
}
Thanks to you all guys. I found the solution by using a generic properly:
public abstract class MyAbstract<T> {
public abstract T CustomValues { get; set; }
}
public class MyImplementation : MyAbstract<MySpecificClass> {
public override MySpecificClass CustomValues { get; set; }
}
In my ASP.NET Core API, I have a DTO class BaseDto and another DerivedDto that inherits from BaseDto and hides some of its properties, because they're required in DerivedDto. I also have a BaseModel class to which both BaseDto and DerivedDto will be mapped through another class Mapper.
Something like the following code:
using System.ComponentModel.DataAnnotations;
public class BaseDto
{
public string Name { get; set; }
}
public class DerivedDto : BaseDto
{
[Required]
public new string Name { get; set; }
}
public class BaseModel
{
public string NameModel { get; set; }
}
public static class Mapper
{
public static BaseModel MapToModel(BaseDto dto) => new BaseModel
{
NameModel = dto.Name
};
}
But it turns out, when passing a DerivedDto object to the MapToModel method, it's trying to access the values of the BaseDto (which are null) instead of the DerivedDto ones.
Is there any way I can achieve this behavior?
I can only think of declaring BaseDto as abstract, but that would prevent me from instantiating it, which I need to do.
You need to declare your BaseDto class property as virtual and then override it in the DerivedDto class as follows:
public class BaseDto
{
public virtual string Name { get; set; }
}
public class DerivedDto : BaseDto
{
public override string Name { get; set; }
}
Also, please fix your Mapper class method. There is no property Name in the BaseModel. It needs to be "NameModel = dto.Name"
Is there a way to make a return type contravariant in inherited types? See the example code below. I need this for Entity Framework.
public class InvoiceDetail
{
public virtual ICollection<Invoice> Invoices { get; set; }
}
public class SalesInvoiceDetail : InvoiceDetail
{
//This is not allowed by the compiler, but what we are trying to achieve is that the return type
//should be ICollection<SalesInvoice> instead of ICollection<Invoice>
public override ICollection<SalesInvoice> Invoices { get; set; }
}
You can apply generics with corresponding constraints
public abstract class InvoiceDetailBase<T> where T : Invoice
{
public virtual ICollection<T> Invoices { get; set; }
}
public class InvoiceDetail : InvoiceDetailBase<Invoice>
{
}
public class SalesInvoiceDetail : InvoiceDetailBase<SalesInvoice>
{
}
I have two similar classes, so I made a parent class, and 2 classes which derive from it. The thing is that they are both trees of only their own type. So for now I have a parent class which holds a reference list of public IList<ParentTreeClass> Children { get; set; }. How can I change the ParentTreeClass to force it to be derived from ParentTreeClass not including it.
To give a bit more specific example, lets call the classes ParentTreeClass, ImportTree and ExportTree.
public class ParentTreeClass {
public ParentTreeClass Parent { get; set; }
public IList<ParentTreeClass> Children { get; set; }
// Other stuff.
}
public class ImportTree : ParentTreeClass {
// Some overrides.
}
public class ExportTree : ParentTreeClass {
// Some other overrides.
}
As said, once I have a ExportTree object, its children and parent should also be ExportTree and no other object.
I have thought about Generics like so:
public class ParentTreeClass<T> {
public T Parent { get; set; }
public IList<T> Children { get; set; }
// Other stuff.
}
But this is not restrictive enought, since I want T to be a child of ParentTreeClass. I tried adding where T : ParentTreeClass. This does not work, cause it tells me to use where T : ParentTreeClass<T>, then I run into issues understanding the second T.
Can I force a tree to be instances of the same type which derives from ParentTreeClass?
It's fairly simple to do.
public class ParentTreeClass<T> where T : ParentTreeClass<T> {
public T Parent { get; set; }
public IList<T> Children { get; set; }
// Other stuff.
}
public class ImportTree : ParentTreeClass<ImportTree> {
// Some overrides.
}
public class ExportTree : ParentTreeClass<ExportTree> {
// Some other overrides.
}
This has the drawback that you can go on to define a class like this:
public class ImportTree2 : ParentTreeClass<ExportTree> {
// Some overrides.
}
But, so long as you're careful with your definitions this works fine.
You could do like this:
public class ParentTreeClass<T> where T: ITree
{
public T Parent { get; set; }
public IList<T> Children { get; set; }
// Other stuff.
}
public interface ITree
{
IList<ITree> Children { get; set; }
ITree Parent { get; set; }
}
public class ImportTree : ParentTreeClass<ITree>, ITree
{
// Some overrides.
}
public class ExportTree : ParentTreeClass<ITree>, ITree
{
// Some other overrides.
}
Restriction is not subclass of parent but it restricts T by ITree implementations only