Tim
Tim

Reputation: 459

c# problem with deriving from generic class

Below are working classes:

public class CatalogManager<T1, T2, T3> where T1 : CatalogDataEntryForm<DataEntryControl>, new()
                                        where T2 : CatalogDataGridForm<DataGridControl>, new()
                                        where T3 : CatalogBusinessObject
{
    public CatalogManager()
    {
        _DataGridFrom = new T2();
        InitGridformToolbarItemeEvents();
    }

}

public class BankDataEntryForm : CatalogDataEntryForm<BankDataEntryControl>
{
}

public class BankDataGridForm : CatalogDataGridForm<BankDataGridControl>
{
}

However, below derived class is complaining with error:

public class BankManager : CatalogManager<BankDataEntryForm, BankDataGridForm, BankBo>
{
    public BankManager()
    {

    }
}

Error message:

Error CS0311 The type 'BankDataEntryForm' cannot be used as type parameter 'T1' in the generic type or method 'CatalogManager'. Error CS0311 The type 'BankDataGridForm' cannot be used as type parameter 'T2' in the generic type or method 'CatalogManager'

Many thanks for your help.

Upvotes: 1

Views: 50

Answers (1)

D-Shih
D-Shih

Reputation: 46239

The issue is a Covariance and Contravariance in Generics as SLaks say DataEntryControl is not the same as BankDataEntryControl, although They are an inheritance relationship.

Starting with the .NET Framework 4, Visual Basic and C# have keywords that enable you to mark the generic type parameters of interfaces and delegates as covariant or contravariant.

so you can try to make the interface for those class.

  • ICatalogDataEntryForm<out T> for CatalogDataEntryForm<T>
  • ICatalogDataGridForm<out T> for CatalogDataGridForm<T>

then let those class implement interface

public interface ICatalogDataEntryForm<out T> 
{ }

public interface ICatalogDataGridForm<out T> 
{ }

public class CatalogDataEntryForm<T> : ICatalogDataEntryForm<T>
{ }
public class CatalogDataGridForm<T> : ICatalogDataGridForm<T>
{}

BankDataGridForm and BankDataEntryForm no need to change.

public class BankDataGridForm : CatalogDataGridForm<BankDataGridControl>
{ 
}
public class BankDataEntryForm : CatalogDataEntryForm<BankDataEntryControl>
{
}

public class BankManager : CatalogManager<BankDataEntryForm, BankDataGridForm,CatalogBusinessObject>
{
    public BankManager()
    {

    }
}

Then let CatalogManager class contract with those interface

public class CatalogManager<T1, T2, T3> where T1 : ICatalogDataEntryForm<DataEntryControl>, new()
                                       where T2 : ICatalogDataGridForm<DataGridControl>, new()
                                       where T3 : CatalogBusinessObject
{
    public CatalogManager()
    {

    }

}

c# online

Upvotes: 2

Related Questions