2012-03-30 9 views
9

我知道我没有这样做,但我也知道有一种方法可以做到这一点。我试图尽可能通用和抽象,否则我的代码会变得非常混乱。所以我在这里使用策略模式作为GetAggregateClient()方法的地狱。在c#中完成这个通用抽象类的最佳方法?

我想要一个名为AbstractAggregate的抽象类,以便它使用泛型。将使用的类型是一系列数据类,它们是BlogItem,ResourceItem和AskItem。这些数据类都从ListItem继承。

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

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

非常感谢。

public static class AggregateHelper 
{ 
    public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources } 
} 

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate<T> GetAggregateClient(AggregateHelper.AggregateTypes type) 
    { 
     switch (type) 
     { 
      case AggregateHelper.AggregateTypes.AskTankTruck: 
       return new AskTankTruckAggregate<AskItem>(); 
      case AggregateHelper.AggregateTypes.TankTruckBlog: 
       return new TankTruckBlogAggregate<BlogItem>(); 
      case AggregateHelper.AggregateTypes.Resources: 
       return new ResourcesAggregate<ResourceItem>(); 
      default: 
       throw new AggregateDoesNotExistException(); 
     } 
    } 
} 

public abstract class AbstractAggregate<T> 
{ 
    public abstract List<T> GetAggregate(Guid[] resourcetypes); 

    public abstract T GetSingle(string friendlyname); 


} 

public class AskTankTruckAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

public class TankTruckBlogAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

回答

3

问题,编译器会抱怨
...是你有一个方法,这就是“打开'(T) - 并且你正在返回封闭的泛型(<AskItem>等),具体类型。
即您必须返回... <T> - ...并且您可以使用该方法执行此操作 - 无论工厂是否不通用,方法仍可以。
至于什么是做到这一点的最好办法,
这是一个“设计”问题多 - 的时间长一点的故事,
我并不完全确定你想实现(也许有些故事背景是什么,怎么多类型的,你可能有等),

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

二,事情是,你不需要一切通用。您的基本聚合器是通用的,但自定义类通常不是,例如像这样...

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

...这是一个实现。
基本上,不是所有'通用'总是最好的方式。你必须有足够的理由或“类型”未知可能被使用。与通用一样,您也支付一定的价格。跨泛型非泛化世界往往是棘手的,并涉及反射,如果你的类型不能通过使用推断等
IMO的错误是使每个提供者的通用 - 因为它只接受一种类型(每个具体),而基地是通用的。就像上面那样。通常泛型也受到每个接口的限制,你可以在哪里/哪里。
但是,你有一个问题,因为从有效的非泛型类转换回泛型上下文不是直的(也要记住有值类型的警告,因为你必须经常以不同的方式对待它)也是如此。
因此,你首先需要类似cast(object)的东西。
我宁愿在这里使用一种IOC方法 - 例如看看autofac(我没有关联,但我喜欢它是如何工作的,很好的框架)。在这种情况下你会做这样的事情......

 container.Register<ProviderBase<AskItem>>(c=> new ProvderA()); 
     container.Register<ProviderBase<BlogItem>>(c => new ProvderB()); 

     // and query later... 

     ProviderBase<AskItem> provider = container.Resolve<ProviderBase<AskItem>>(); 

希望这有助于一些...

+0

感谢您的详细解释。我原本选择了一个不同的答案,但你说服了我。谢谢您的帮助! – apexdodge 2012-03-30 22:15:49

+0

np :) - 有很多方法/答案,只要坚持保持逻辑(每一点通常有其目的或不保证一个地方),你会没事的。并看看国际奥委会,autofac,你会喜欢它(比泛型:)更多 – NSGaga 2012-03-30 22:29:57

1

我不知道我知道你想什么来实现,但也许是这样的

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate<T> GetAggregateClient<T>() 
    { 
     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<T> 
{ 
    public abstract List<T> GetAggregate(Guid[] resourcetypes); 

    public abstract T GetSingle(string friendlyname); 
} 

public class AskTankTruckAggregate : AbstractAggregate<AskItem> 
{ 
    //not implemented yet 
} 

public class TankTruckBlogAggregate : AbstractAggregate<BlogItem> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate : AbstractAggregate<ResourceItem> 
{ 
    //not implemented yet 
} 
+0

我不认为你可以做 'T是BlogItem' - 你需要T的值 - 或者 '的typeof(T).Equals(typeof运算(BlogItem))' 什么的 - 只是作为一个旁注 – NSGaga 2012-03-30 20:17:02

+0

@NSGaga:是的,你可能是对的。 – Gebb 2012-03-30 20:19:22

1

我想是因为通用和抽象越好,否则我代码将变得非常混乱。

这是一种误解。通用/抽象实际上可能使一个简单的问题复杂化。清理代码的关键是封装。与继承或泛型非常不同。

在这种情况下,我认为构图将是一个更好的选择,而不是继承。通过一组适配器,您可以拥有一个可以将每个实体分配到的共同对象。例如:

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) 
    { 
     .... 
    } 
} 
1

如何:

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<T> GetAggregateClient<T> 
     (AggregateHelper.AggregateTypes type) 
    { 
     switch (type) 
     { 
      case AggregateHelper.AggregateTypes.AskTankTruck: 
       return new AskTankTruckAggregate<T>(); 
      case AggregateHelper.AggregateTypes.TankTruckBlog: 
       return new TankTruckBlogAggregate<T>(); 
      case AggregateHelper.AggregateTypes.Resources: 
       return new ResourcesAggregate<T>(); 
      default: 
       throw new ArgumentException(); 
     } 
    } 
} 

public abstract class AbstractAggregate<T> 
{ 
    public abstract List<T> GetAggregate(Guid[] resourcetypes); 
    public abstract T GetSingle(string friendlyname); 
} 

public class AskTankTruckAggregate<T> : AbstractAggregate<T> 
{ 
    public override List<T> 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<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

例子:

AbstractAggregate<BlogItem> foo3 = 
    AbstractAggregateFactory.GetAggregateClient<BlogItem>(AggregateHelper.AggregateTypes.AskTankTruck); 
foo3.GetSingle("test"); 
0

有一点是可能清楚的是,你的设计是有点瑕疵。打开类型并不是在通用方法中做的最好的事情,它违背了它的目的。但是不清楚的是你的课程的目的是什么。

的一些思考:

1)查看你对类AskItemAskTankTruckAggregate<T>等我不认为后者是一个通用类,它是一个非常特殊的类,紧耦合AskItem。我会重新设计它像

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem 
    { 
     //use reflection to find the type that inherits AbstractAggregate<T> 

     //instantiate the type 

     //cast to AbstractAggregate<T> and return 
    } 
} 

public class AskTankTruckAggregate : AbstractAggregate<AskItem> 
{ 
    //not implemented yet 
} 

public class TankTruckBlogAggregate : AbstractAggregate<BlogItem> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate : AbstractAggregate<ResourceItem> 
{ 
    //not implemented yet 
} 

这样称呼它:

AbstractAggregateFactory.GetAggregateClient<AskItem>(); //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<T> GetAggregateClient<T>() where T : ListItem, new() 
    { 
     return (AbstractAggregate<T>)new T().Create(); 
    } 
} 

public class AskTankTruckAggregate : AbstractAggregate<AskItem> 
{ 
    //not implemented yet 
} 

public class TankTruckBlogAggregate : AbstractAggregate<BlogItem> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate : AbstractAggregate<ResourceItem> 
{ 
    //not implemented yet 
} 

这样称呼它:

AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc 

3)或相同的,但要多一点强类型,使用泛型:

public abstract class ListItem<T> where T : ListItem<T> //or interface 
{ 
    protected abstract AbstractAggregate<T> Create(); 
} 
public class AskItem : ListItem<AskItem> { //implement to return AskTankTruckAggregate 
} 
public class BlogItem : ListItem<BlogItem> { //implement to return TankTruckBlogAggregate 
} 
public class ResourceItem : ListItem<ResourceItem> { //implement to return ResourcesAggregate 
} 

public static class AbstractAggregateFactory 
{ 
    public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem, new() 
    { 
     return new T().Create(); 
    } 
} 

public class AskTankTruckAggregate : AbstractAggregate<AskItem> 
{ 
    //not implemented yet 
} 

public class TankTruckBlogAggregate : AbstractAggregate<BlogItem> 
{ 
    //not implemented yet 
} 

public class ResourcesAggregate : AbstractAggregate<ResourceItem> 
{ 
    //not implemented yet 
} 

呼叫它像:

AbstractAggregateFactory.GetAggregateClient<AskItem>(); //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<AskItem>(); 
      case AggregateTypes.TankTruckBlog: 
       return new TankTruckBlogAggregate<BlogItem>(); 
      case AggregateTypes.Resources: 
       return new ResourcesAggregate<ResourceItem>(); 
      default: 
       throw new AggregateDoesNotExistException(); 
     } 
    } 
} 

public abstract class AbstractAggregate 
{ 

} 

public abstract class AbstractAggregate<T> : AbstractAggregate 
{ 

} 

//or change the definition to AskTankTruckAggregate : AbstractAggregate<AskItem> 
public class AskTankTruckAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

//or change the definition to TankTruckBlogAggregate : AbstractAggregate<BlogItem> 
public class TankTruckBlogAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

//or change the definition to ResourcesAggregate : AbstractAggregate<ResourceItem> 
public class ResourcesAggregate<T> : AbstractAggregate<T> 
{ 
    //not implemented yet 
} 

这样称呼它:

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

海事组织,这种方法比反射的方法更糟糕。在将来很容易忘记一些枚举检查。


总之,第三看起来对我最好,但又不知道你的设计目标,它很难预测。几点建议:

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

  2. 如果你需要一个枚举来表示类型,不要使它嵌套。嵌套的公共类型很难打电话。拿出包装静态类(如我的第五种方法)。

  3. 将您的基类重命名为Aggregate<T>或。再次,“抽象”使它更多地关于实现,相当不必要。