use*_*491 7 c# generics methods virtual
我有一些像这样的基类:
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)
{
//...
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我有一个Windows窗体基类,如下所示:
public class BaseForm: Form
{
public virtual AbstractManager<T> GetManager<T>() where T: AbstractData
{
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
和派生形式:
public class PersonForm: BaseForm
{
public override AbstractManager<T> GetManager<T>()
{
return new PersonManager();
}
}
Run Code Online (Sandbox Code Playgroud)
问题是,我一直在PersonForm类上遇到编译错误:
无法将类型'PersonManager'隐式转换为'AbstractManager <T>'
有没有一种方法可以创建这个虚方法,并从BaseForm派生的每个类都返回AbstractManager的具体表示?
如果我摆脱了AbstractManager类上的泛型,那么我编译好(通过一些代码更改),但是GetAll方法不能返回一个List<T>.它必须返回一个List<AbstractData>,这会导致转换List<Person>为List<AbstractData>.
任何帮助,将不胜感激.
Eri*_*ert 16
首先,请不要这样做:
class C<T>
{
void M<T>(T t) { }
}
Run Code Online (Sandbox Code Playgroud)
现在我们在范围内有两个名为T的东西,它们是不同的.这是合法的,但非常令人困惑.为类型参数选择更好的名称.
让我们简化你的例子:
class FruitBasket<T> where T : Fruit { }
class AppleBasket : FruitBasket<Apple> { }
class C
{
public static FruitBasket<T> GetBasket<T>() where T: Fruit
{
return new AppleBasket();
}
}
Run Code Online (Sandbox Code Playgroud)
现在你明白为什么这是错的吗?如果有人打电话给C.GetBasket<Orange>()你他们一篮子苹果怎么办?
任何帮助,将不胜感激.
走出一个洞的第一步是什么?停止挖掘.
你有Genericity Happiness Disease,这对C#程序员来说是很常见的,他们正在发现泛型类型系统的强大功能,然后想要将它用于任何有意义的事情.停止尝试捕获泛型类型系统中业务流程中的所有关系; 这不是它的设计目标.
测试是:你能说"苹果篮子是一篮子苹果,苹果是一种水果",并且有一个不是程序员同意你的人吗?是.你能否说"一个人经理是人是一种抽象数据的人的抽象经理",并且有一个不是程序员的人同意你的看法?不会.然后,您无法在类型系统中成功建模业务域.重新开始,避免使用泛型,并尝试在有意义的类型之间建立关系.
Mic*_*Liu 11
通过声明
public virtual AbstractManager<T> GetManager<T>() where T: AbstractData
Run Code Online (Sandbox Code Playgroud)
在BaseForm,你允诺每类源自BaseForm支持GetManager的任何类型T.例如,如果您有另一个AbstractData名为的子类Invoice,那么您可以编写
personForm.GetManager<Invoice>()
Run Code Online (Sandbox Code Playgroud)
并且PersonForm预计将返回InvoiceManager.
如果您希望每个派生的类只BaseForm支持一种类型,那么将type参数从:移动到:GetManagerTTGetManagerBaseForm
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();
}
}
Run Code Online (Sandbox Code Playgroud)
更新: Chad Henderson指出Windows窗体设计器无法处理通用基类.如果这对您来说是个问题,那么您可以尝试另一种方法:
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();
}
}
Run Code Online (Sandbox Code Playgroud)