C# Covariant Returns for Auto-Implemented Properties - oop

As you know, C# 9.0 (.Net 5) now allows Covariant Returns. I need help applying this to a set of classes having Auto-Implemented properties.
I have two abstract classes that represent financial bank accounts and transactions. I made them abstract since I will pull data from various data sources and while the main properties will be common across all sources, each source may have additional fields I want to keep. A 1 to Many relationship exists between both classes (1 account has many transactions AND 1 transaction belongs to only 1 account).
public abstract class BankAccount
{
public string Name { get; set; }
public IList<Transaction> Transactions { get; set; } = new List<Transaction>();
...
}
public abstract class Transaction
{
public string Name { get; set; }
public virtual BankAccount BankAccount { get; set; } // This doesn't work unless I remove set;
...
}
And here is an example of the concrete implementations
public class PlaidBankAccount : BankAccount
{
public string PlaidId { get; set; }
...
}
public class PlaidTransaction : Transaction
{
public string PlaidId { get; set; }
public override PlaidBankAccount BankAccount { get; set; } // This doesn't work unless I remove set;
...
}
What I want to do is to override the base class getters and setters so that they use derived classes. For example:
If I create an instance of the concrete transaction and call the BankAccount getter, I want to get an instance of the derived PlaidBankAccount not the base BankAccount.
What I've found is that when I only define virtual getter in the base class and override it in the derived class, it works. But just as I add both properties {get;set;}, I get the same error as in previous C# versions:
error CS1715: 'PlaidTransaction.BankAccount': type must be 'BankAccount' to match overridden member 'Transaction.BankAccount'
How could I fix this?

In C# 9 properties are only able to have co-variant returns when they are readonly, so unfortunately, no set; is possible.
An overriding property declaration must specify exactly the same access modifier, type, and name as the inherited property. Beginning with C# 9.0, read-only overriding properties support covariant return types. The overridden property must be virtual, abstract, or override.
From the Microsoft Docs - Override keyword

Related

Designing a hierarchy of abstract classes and using it in EF Core

I am using .NET Core with Entity Framework Core to build a finance app and I want to know how to make my design better.
I have a 1 to Many relationship between two entities, BankAccount and Transaction. In a way that:
1 Account can have many Transactions
1 Transaction Belongs to 1 Account
However, I want to include bank accounts and transactions coming from different 3P sources. And while this relationship and the main fields are common across different sources, each source has a unique set of properties I want to keep.
To achieve this I decided to define these entities as abstract classes. This way, you can only instantiate concrete versions of these entities, each coming from a particular data source.
public abstract class Transaction : BaseEntity
{
public DataSource Source { get; private set; }
public decimal Amount { get; private set; }
public DateTime Date { get; private set; }
public string Name { get; private set; }
public BankAccount BankAccount { get; private set; }
public Guid BankAccountId { get; private set; }
...
}
public abstract class BankAccount : BaseEntity
{
public DataSource Source { get; private set; }
public string Name { get; private set; }
public Balance Balance { get; private set; }
public IEnumerable<Transaction> Transactions {get; private set;}
...
}
Here is a trimmed down example of the concrete implementations:
public class PlaidTransaction : Transaction
{
public string PlaidId { get; private set; }
private PlaidTransaction() : base() { }
public PlaidTransaction(decimal amount, DateTime date, string name, Guid bankAccountId, string plaidId) : base( amount, date, name, bankAccountId)
{
PlaidId = plaidId;
}
}
public class PlaidBankAccount : BankAccount
{
public string PlaidId { get; private set; }
...
}
I am using .Net Core with Entity Framework Core to persist my data and I managed to store my concrete classes all in the same table (TPH approach)
This works great and now all my entities live under the same table. So I can either query all Transactions or those of a certain type using LINQ's OfType<T> extension.
DbSet<Transaction> entities = _context.Set<Transaction>();
IEnumerable<PlaidTransaction> plaidTransactions = entities.OfType<PlaidTransaction>();
However, when I access my BankAccount field from my concrete Transaction I don't get the concrete instance. So something like this doesn't work.
plaidTransactions.Where((t) => t.BankAccount.PlaidId)
Instead I have to cast it:
plaidTransactions.Where((t) => (t.BankAccount as PlaidBankAccount).PlaidId)
What can I do to avoid casting everywhere? I feel there's a missing piece in my design that would make all my code easier. I was thinking of overriding the getters on my concrete classes but I don't know if I can return a derived class to a base class method. Maybe I should move to generics but 1) I still want to keep the fixed relationship between these entities and 2) how would EF Core handle this?

WCF serialization issue when moving existing class properties to newly created base class

I'm seeing the serialization issue at the client side for the following scenario.
Let's say we have the following class and method in our service code
[DataContract]
public class Derived
{
[DataMember]
public string A { get; set; }
[DataMember]
public string B { get; set; }
[DataMember]
public string C { get; set; }
[DataMember]
public string D { get; set; }
}
and the service interface has the method
[OperationContract]
Derived GetDerived();
Implementation of the method -
public Derived GetDerived()
{
var d = new Derived() {A = "A", B = "B", C = "C", D = "D"};
return d;
}
For this WCF service if I create the client proxy (by adding service reference) and do the GetDerived() call, everything works fine.
Let's change the entity in service code little bit
[DataContract]
public class Base
{
[DataMember]
public string B { get; set; }
}
[DataContract]
public class Derived : Base
{
[DataMember]
public string A { get; set; }
[DataMember]
public string C { get; set; }
[DataMember]
public string D { get; set; }
}
So in this case I created a new Base class and moved property 'B' to the Base class. With the same old proxy at the client side, if I do GetDerived call, I do not see the value of A properly serialized at the client side. However, the SOAP message for previous version and the current version is the same (only order changed). I came across this http://msdn.microsoft.com/en-us/library/ms729813.aspx article explaining the ordering. Since I moved 'B' to base class, I don't see anyway to control it's order in derived class.
Is there any workaround to this problem? This breaks the backward compatibility to the client.
On the other hand, If I add the new property, let's say C1 to Derived class (or any existing class), it changes the order as well. How come this doesn't break the client? vs. the scenario that I mentioned earlier.
Using the example above, I overloaded the property "B" in the derived class and had it refer to the Base class (I'm working in VB, sorry):
#region "This shenanigans prevents breaking the contract when moving some properties to the base class.
<DataMember()> Public Overloads Property B() As String
Get
Return MyBase.B
End Get
Set(value As String)
MyBase.B = value
End Set
End Property
#End Region
This way my base class methods can still operate on B. If we ever get around to implementing wcf versioning, or have some other need to change the contract, I can strip out that overload in the derived class and everything should still just work.
-JG

ORM with entity classes and domain interfaces/classes

I'm trying to decide how to handle domain-level classes and interfaces with respect to objects populated via ORM (NHibernate in this case). I've mocked up a very simple scenario that helps to illustrate my current situation.
public interface ICar
{
public bool PassesEmisionStandards(string state);
public int Horsepower { get; set; }
public string Model { get; set; }
}
public class CarFromDB
{
public int Horsepower { get; set; }
public string Model { get; set; }
}
public class ModelT : CarFromDB, ICar
{
public bool PassesEmissionStandards(string state)
{
return false;
}
public override string ToString()
{
return Model + " with " + Horsepower + " ponies";
}
}
In this case, CarFromDB is the class that's got the mapping via NHibernate to my database. ICar is the interface that my UI/Controller code is handling. ModelT is one of the classes that have instances passed to the UI.
In my actual domain, the PassesEmissionStandards is a complicated method that differs significantly among the different derived classes, and the CarFromDB class has a dozen simple properties along with references to other classes, both singly and in lists. This information is all used in the PassesEmissionStandards equivalent.
I'm confused about the best way to end up with my derived classes decorated with the interface when I start with a populated base class from the ORM. The ideas I've come up with to try to handle this are:
Decorate CarFromDB with ICar and try to come up with a clean way to implement the extensive PassesEmissionStandards method within it or by calling out to other classes for help
Use AutoMapper or the equivalent + a factory to transform my base class objects into derived class objects
Since the derived class type can be identified from a property in the base class, mapp my derived classes for NHibernate and find some way to hook into NHibernate to instruct it which mapped derived class to use.
I feel like this must be a very common issue, but I searched around SO and other places without finding any solid guidelines. Please note: I'm relatively new to ORM and domain modelling and very new to NHibernate. Any help is appreciated.
I don't think that I understand your problem, why canĀ“t you use:
public interface ICar
{
public bool PassesEmisionStandards(string state);
public int Horsepower { get; set; }
public string Model { get; set; }
}
public abstract class CarBase : ICar
{
public int Horsepower { get; set; }
public string Model { get; set; }
public abstract bool PassesEmisionStandards(string state);
}
Or if CarBase is used for all derived classes too, you might want to use strategy pattern
public interface IEmissionCalculator
{
void Calculate(IEmissionCalculatorContext context);
}
public CarBase : ICar
{
internal void Assign(IEmissionCalculator calculator){}
public bool PassesEmisionStandards(string state)
{
//assign all info needed for calculations
var ctx = new IEmissionCalculatorContext { };
return _calculator.Check(ctx);
}
}
You can use the same DB-class, but assign different emission caluclations depending of the type of car.
If that doesn't work either, I would use automapper.

Fluent NHibernate - Map 2 Identical classes to same table

I've seen this (unanswered) question asked once before, but in a different context. I'm looking to have two domain objects map to the same table, WITHOUT a discriminator. The two classes are:
public class Category
{
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
public virtual ReadOnlyCategory ParentCategory { get; private set; }
}
and
public class ReadOnlyCategory
{
public virtual int Id { get; private set; }
public virtual string Name { get; private set; }
public virtual ReadOnlyCategory ParentCategory { get; private set; }
}
The main difference is that all public properties of ReadOnlyCategory are read-only. My idea here is that I want all users of this class to know that they should only mess with the category they are currently 'looking' at, and not any other categories in the hierarchy. (I've left off other properties regarding the subcategories.)
Clearly, in the database, Category and ReadOnlyCategory are the same thing, and NHibernate should treat them very similarly when persisting them. There are three problems wrapped into one here:
1) How do I do the mapping?
2) When instantiating the objects, how do I control whether I instantiate Category or ReadOnlyCategory?
3) When persisting the objects, will the mapping be smart enough, or do I need to use an extensibility point here?
Any pointers on how I can get this to happen?
(Or am I crazy?)
This looks like wrong object model design to me. I don't see a good reason to introduce a new class just for authorisation reasons (whether user allowed to modify a given category object?). You may as well use one class and throw for example InvalidOperationException if an end user is not supposed to modify a category.

Is the properties in Entity must be virtual when using FluentNhibernate?

Which entity FluentNHibernate uses as entity
I create some entity in Domain(or BLL), such as the following:
public class Role
{
public long ID { get; protected set; }
public string Name { get; set; }
public string Description { get; set; }
public List<User> Users { get; set; }
public Role()
{
Users = new List<User>();
}
}
And I want make use of FlunetNHibernate to map them, but get errors:
The following types may not be used as proxies:
Freeflying.Domain.Core.Profile: method get_ID should be 'public/protected virtual' or 'protected internal virtual'
Yes, I recall the programmer requirement when use FluentNHibernate, the entity should be like this:
public class Role
{
public virtual long ID { get; protected set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
}
But It looks wired. Do you think so? How do you do when using FluentNHibernate? I don't want go back to Domain layer and add virtual for every property.
This is a basic requirement for using NHibernate; It allows NHibernate to generate a proxy class that descends from your class for lazy loading and such.
I have not seen a method of removing this requirement, though if such a thing is possible it would mean that you could not use lazy loading of objects and/or properties.
Here's a blog post that explains this a bit more; It also offers a way to avoid marking your properties as virtual, although I would really recommend that you do not use this method (marking classes to avoid lazy loading) as the benefits of lazy loading in most circumstances far outweigh the cost of making your properties virtual.