Creating a virtual shared method in C #

I have base classes:

public class AbstractData { public int ID { get; set; } } public class Person: AbstractData { public string Name { get; set; } } public class AbstractManager<T> where T: AbstractData { public virtual List<T> GetAll() { } public virtual T GetOne(int id) { } } public class PersonManager: AbstractManager<Person> { public override List<Person> GetAll() { //... } public override Person GetOne(int id) { //... } } 

Now I have a Windows Forms base class, for example:

 public class BaseForm: Form { public virtual AbstractManager<T> GetManager<T>() where T: AbstractData { return null; } } 

and derivative form:

 public class PersonForm: BaseForm { public override AbstractManager<T> GetManager<T>() { return new PersonManager(); } } 

The problem is that I keep getting compilation errors of the PersonForm class:

Cannot implicitly convert type 'PersonManager' to 'AbstractManager <T>'

Is there a way I can create this virtual method and each class derived from BaseForm returns a specific AbstractManager view?

If I get rid of generic in the AbstractManager class, then I compile OK (with a few code changes), but then the GetAll method cannot return List<T> . It would have to return List<AbstractData> instead, which causes problems when converting from List<Person> to List<AbstractData> .

Any help would be appreciated.

+7
generics methods c # virtual
source share
2 answers

First of all, never do this:

 class C<T> { void M<T>(T t) { } } 

Now we have two things called T by volume, and they are different. This is legal, but extremely confusing. Choose the best names for your type options.

Simplify your example:

 class FruitBasket<T> where T : Fruit { } class AppleBasket : FruitBasket<Apple> { } class C { public static FruitBasket<T> GetBasket<T>() where T: Fruit { return new AppleBasket(); } } 

Now you see why this is wrong? What if someone calls C.GetBasket<Orange>() and you pass them a basket of apples?

Any help would be appreciated.

What step flew out of the pit? STOP DIGGING .

You have a birth-related disease that is characteristic of C # programmers who discover the power of a generic type system and then want to use it for anything that makes sense or not. Do not try to capture all the relationships in your business process in a general type system; this is not what it was intended for.

Test: can you say: "an apple basket is a basket of apples, where apples are a kind of fruit," and with someone who is not a programmer, I agree with you? Yes. Can you say that "the personnel manager is an abstract manager of persons in which a person is a kind of abstract data" and with someone who is not a programmer, I agree with you? Not. Then you do not successfully model the business domain in the type system . Start over, avoid generics and try to find relationships between types that make sense.

+15
source share

Announcing

 public virtual AbstractManager<T> GetManager<T>() where T: AbstractData 

in BaseForm , you promise that every class derived from BaseForm supports GetManager for any type T For example, if you have another subclass of AbstractData called Invoice , you can write

 personForm.GetManager<Invoice>() 
Expected that

and PersonForm will return the InvoiceManager .

If you want each class derived from BaseForm to support GetManager for only one type T , move the parameter of type T from GetManager to BaseForm :

 public class BaseForm<T>: Form where T: AbstractData { public virtual AbstractManager<T> GetManager() { return null; } } public class PersonForm: BaseForm<Person> { public override AbstractManager<Person> GetManager() { return new PersonManager(); } } 

UPDATE: Chad Henderson indicates that a Windows Forms developer cannot handle base classes. If this is a problem for you, you can try an alternative approach:

 public interface IForm<T> where T: AbstractData { AbstractManager<T> GetManager(); } public class BaseForm: Form { // ... base functionality that doesn't depend on T ... } public class PersonForm: BaseForm, IForm<Person> { public AbstractManager<Person> GetManager() { return new PersonManager(); } } 
+11
source share

All Articles