Reputation: 164
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?
Upvotes: 6
Views: 1574
Reputation: 407
As already answered by @ehiller, it's only possible to have covariant returns if a property is readonly, but you can still set its value when calling the constructor. Here's an example:
public interface IBase {
void Method1();
}
public interface IDerived : IBase {
void Method2();
}
public class Base {
public virtual IBase Property { get; }
public Base(IBase b) {
Property = b; // No setter, but it's legal to set the value here.
}
public void CallMethod1() {
Property.Method1();
}
}
public class Derived : Base {
// Property with covariant return.
public override IDerived Property { get; }
public Derived(IDerived d) : base(d) {
Property = d; // property must also be set here.
}
public void CallMethod2() {
Property.Method2();
}
}
Upvotes: 0
Reputation: 1547
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
Upvotes: 8