Pedro L
Pedro L

Reputation: 164

C# Covariant Returns for Auto-Implemented Properties

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

Answers (2)

metator
metator

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:

  1. Define a couple of types that are going to be used to declare the properties (using interfaces in this example):
public interface IBase {
    void Method1();
}

public interface IDerived : IBase {
    void Method2();
}
  1. Define the types that declare the properties:
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

ehiller
ehiller

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

Related Questions