在c#中执行此通用抽象类的最佳方法是什么?

我知道我做得不对,但我也知道有办法做到这一点。 我试图尽可能地通用和抽象,否则我的代码将变得非常混乱。 所以我在这里使用策略模式作为GetAggregateClient()方法。

我想要一个名为AbstractAggregate的抽象类,以便它使用generics。 将使用的类型是一系列数据类,即BlogItem,ResourceItem和AskItem。 这些数据类都inheritance自ListItem。

这就是背景信息。 这里的问题是我希望GetAbstractAggregate()返回一个实现AbstractAggregate的客户端类的实例,其中指定的项目类型取决于传入的枚举。但是,我不能返回“AbstractAggregate”。 编译器不会让我这样,因为AbstractAggregateFactory类不是通用的。

有没有人有最好的方法来做到这一点?

非常感谢。

public static class AggregateHelper { public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources } } public static class AbstractAggregateFactory { public static AbstractAggregate GetAggregateClient(AggregateHelper.AggregateTypes type) { switch (type) { case AggregateHelper.AggregateTypes.AskTankTruck: return new AskTankTruckAggregate(); case AggregateHelper.AggregateTypes.TankTruckBlog: return new TankTruckBlogAggregate(); case AggregateHelper.AggregateTypes.Resources: return new ResourcesAggregate(); default: throw new AggregateDoesNotExistException(); } } } public abstract class AbstractAggregate { public abstract List GetAggregate(Guid[] resourcetypes); public abstract T GetSingle(string friendlyname); } public class AskTankTruckAggregate : AbstractAggregate { //not implemented yet } public class TankTruckBlogAggregate : AbstractAggregate { //not implemented yet } public class ResourcesAggregate : AbstractAggregate { //not implemented yet } 

问题,编译器抱怨
…是你有一个’开放’(T)的方法 – 你正在返回封闭的generics(与等),具体类型。
即你必须返回… – …你可以用这个方法做到这一点 – 无论工厂是不是通用的,方法都可以。
至于什么是最好的方法,
这更像是一个“设计”问题 – 还有一个更长的故事,
我不完全确定你想要实现的目标(也许是一些背景故事,你可能有多少类型等),

首先,你不应该(一般来说,作为一种最佳做法或一些’感觉良好’因素)
从ListIteminheritance你的项目 – 使用你的其他一些基类 – 如果你需要一个集合使用像List这样的通用 – 或者创建你自己的IList实现等。

其次,事情是你不需要通用的一切。 您的基本聚合器是通用的,但自定义类通常不是这样的…

 abstract class ItemBase { } class AskItem : ItemBase { } class BlogItem : ItemBase { } class ProvderA : ProviderBase { public override AskItem Get() { throw new NotImplementedException(); } } class ProvderB : ProviderBase { public override BlogItem Get() { throw new NotImplementedException(); } } abstract class ProviderBase where T : ItemBase { public abstract T Get(); } class Program { static void Main(string[] args) { ProviderBase provider = GetProvider(); var item = provider.Get(); } static ProviderBase GetProvider() where T : ItemBase { if (typeof(T) == typeof(AskItem)) return (ProviderBase)(object)new ProvderA(); if (typeof(T) == typeof(BlogItem)) return (ProviderBase)(object)new ProvderB(); return null; } } 

……这是一个实现。
基本上,并非所有“通用”都是最好的方式。 你必须有足够的理由或’类型’未知可能被使用。 与通用一样,您也需支付一定的价格。 将generics转换为非generics世界通常很棘手,如果您的类型无法通过使用等推断,则涉及reflection。
IMO的错误是使每个提供者都是通用的 – 因为它只接受一种类型(每种具体),而基础是通用的。 就像上面那样。 通常,通用也会在每个接口的位置受到限制。
但是你有一个问题,因为从一个有效的非generics类中回退到generics上下文并不是直的(另外还要记住有值类型的警告,因为你必须经常有时区别对待),反之亦然好。
因此,您首先需要像cast(object)这样的东西。
我宁愿在这里使用一些IOC方法 – 例如看看autofac (我没有关联,但我喜欢它是如何工作的,很好的框架)。 在那种情况下,你会做类似……

  container.Register>(c=> new ProvderA()); container.Register>(c => new ProvderB()); // and query later... ProviderBase provider = container.Resolve>(); 

希望这有助于一些……

我不确定我理解你想要实现的目标,但也许就是这样

 public static class AbstractAggregateFactory { public static AbstractAggregate GetAggregateClient() { if(T is AskItem) return new AskTankTruckAggregate(); if(T is BlogItem) return new TankTruckBlogAggregate(); if(T is ResourceItem) return new ResourcesAggregate(); } } public abstract class AbstractAggregate { public abstract List GetAggregate(Guid[] resourcetypes); public abstract T GetSingle(string friendlyname); } public class AskTankTruckAggregate : AbstractAggregate { //not implemented yet } public class TankTruckBlogAggregate : AbstractAggregate { //not implemented yet } public class ResourcesAggregate : AbstractAggregate { //not implemented yet } 

我试图尽可能地通用和抽象,否则我的代码将变得非常混乱。

这是一种误解。 通用/抽象实际上可以使一个简单的问题复杂化。 清理代码的关键是封装。 与inheritance或generics有很大不同。

在这种情况下,我认为组合将是一个更好的选择,而不是inheritance。 使用一组适配器,您可以拥有一个可以访问每个实体的公共对象。 例如:

 interface ICommon { ... } class AskAdaptor: ICommon { private readonly Ask ask; publick AskAdaptor(Ask ask) { this.ask = ask; } } class AskAdaptor: ICommon { private readonly Blog blog; publick AskAdaptor(Blog blog) { this.blog = blog; } } class AskAdaptor: ICommon { private readonly Resource resource; publick AskAdaptor(Resource resource) { this.resource = resource; } } class CommonAggregate { public void Add(ICommon common) { .... } } 

这个怎么样:

 public static class AggregateHelper { public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources } } public class AskItem { } public class BlogItem { } public class ResourceItem { } public static class AbstractAggregateFactory { public static AbstractAggregate GetAggregateClient (AggregateHelper.AggregateTypes type) { switch (type) { case AggregateHelper.AggregateTypes.AskTankTruck: return new AskTankTruckAggregate(); case AggregateHelper.AggregateTypes.TankTruckBlog: return new TankTruckBlogAggregate(); case AggregateHelper.AggregateTypes.Resources: return new ResourcesAggregate(); default: throw new ArgumentException(); } } } public abstract class AbstractAggregate { public abstract List GetAggregate(Guid[] resourcetypes); public abstract T GetSingle(string friendlyname); } public class AskTankTruckAggregate : AbstractAggregate { public override List GetAggregate(Guid[] resourcetypes) { throw new NotImplementedException(); } public override T GetSingle(string friendlyname) { Console.WriteLine(friendlyname); Type whats_t = typeof(T); return default(T); } } public class TankTruckBlogAggregate : AbstractAggregate { //not implemented yet } public class ResourcesAggregate : AbstractAggregate { //not implemented yet } 

例:

 AbstractAggregate foo3 = AbstractAggregateFactory.GetAggregateClient(AggregateHelper.AggregateTypes.AskTankTruck); foo3.GetSingle("test"); 

有一件事可能很清楚,那就是你的设计存在一些缺陷。 打开类型并不是一个通用方法中最好的方法,它会破坏它的目的。 但是不清楚的是你的课程的目的是什么。

一些猜测:

1)看到你的对类AskItemAskTankTruckAggregate等我不认为后者必须是一个generics类,它是一个非常特殊的类,与AskItem紧密耦合。 我会重新设计它

 public static class AbstractAggregateFactory { public static AbstractAggregate GetAggregateClient() where T : ListItem { //use reflection to find the type that inherits AbstractAggregate //instantiate the type //cast to AbstractAggregate and return } } public class AskTankTruckAggregate : AbstractAggregate { //not implemented yet } public class TankTruckBlogAggregate : AbstractAggregate { //not implemented yet } public class ResourcesAggregate : AbstractAggregate { //not implemented yet } 

称之为:

 AbstractAggregateFactory.GetAggregateClient(); //etc 

2)另一种方法:将聚合创建作业委托给ListItems。

 public abstract class ListItem //or interface { protected abstract object Create(); } public class AskItem : ListItem { //implement to return AskTankTruckAggregate } public class BlogItem : ListItem { //implement to return TankTruckBlogAggregate } public class ResourceItem : ListItem { //implement to return ResourcesAggregate } public static class AbstractAggregateFactory { public static AbstractAggregate GetAggregateClient() where T : ListItem, new() { return (AbstractAggregate)new T().Create(); } } public class AskTankTruckAggregate : AbstractAggregate { //not implemented yet } public class TankTruckBlogAggregate : AbstractAggregate { //not implemented yet } public class ResourcesAggregate : AbstractAggregate { //not implemented yet } 

称之为:

 AbstractAggregateFactory.GetAggregateClient(); //etc 

3)或者相同,但使用generics使其更加强烈打字:

 public abstract class ListItem where T : ListItem //or interface { protected abstract AbstractAggregate Create(); } public class AskItem : ListItem { //implement to return AskTankTruckAggregate } public class BlogItem : ListItem { //implement to return TankTruckBlogAggregate } public class ResourceItem : ListItem { //implement to return ResourcesAggregate } public static class AbstractAggregateFactory { public static AbstractAggregate GetAggregateClient() where T : ListItem, new() { return new T().Create(); } } public class AskTankTruckAggregate : AbstractAggregate { //not implemented yet } public class TankTruckBlogAggregate : AbstractAggregate { //not implemented yet } public class ResourcesAggregate : AbstractAggregate { //not implemented yet } 

称之为:

 AbstractAggregateFactory.GetAggregateClient(); //etc 

4)最后,可能会使返回类型不那么通用吗? 涉及开关案例,我不喜欢它。

 public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources } public static class AbstractAggregateFactory { public static AbstractAggregate GetAggregateClient(AggregateTypes type) { switch (type) { case AggregateTypes.AskTankTruck: return new AskTankTruckAggregate(); case AggregateTypes.TankTruckBlog: return new TankTruckBlogAggregate(); case AggregateTypes.Resources: return new ResourcesAggregate(); default: throw new AggregateDoesNotExistException(); } } } public abstract class AbstractAggregate { } public abstract class AbstractAggregate : AbstractAggregate { } //or change the definition to AskTankTruckAggregate : AbstractAggregate public class AskTankTruckAggregate : AbstractAggregate { //not implemented yet } //or change the definition to TankTruckBlogAggregate : AbstractAggregate public class TankTruckBlogAggregate : AbstractAggregate { //not implemented yet } //or change the definition to ResourcesAggregate : AbstractAggregate public class ResourcesAggregate : AbstractAggregate { //not implemented yet } 

称之为:

 AbstractAggregateFactory.GetAggregateClient(AggregateTypes.AskTankTruck); //etc 

Imo,这种方法比reflection方法更糟糕。 很容易忘记将来的一些枚举。


最重要的是,3号看起来对我来说是最好的,但是在不知道你的设计目标的情况下,它很难预测。 几点建议:

  1. 您的工厂名称听起来更像AggregateFactory 。 其中的“摘要”使其更多地涉及实施。

  2. 如果您需要枚举来表示类型,请不要嵌套。 嵌套的公共类型更难调用。 取出包装静态类(如我的第5种方法)。

  3. 将基类重命名为AggregateAggregateBase 。 再次“抽象”使其更多地涉及实施,非常不必要。