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

时间:2012-03-30 19:36:58

标签: c# generics refactoring abstract-class strategy-pattern

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

我想要一个名为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
}

5 个答案:

答案 0 :(得分:3)

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

首先,你不应该(一般来说,作为一种最佳做法或一些'感觉良好'因素) 从ListItem继承你的项目 - 使用你的其他一些基类 - 如果你需要一个集合使用像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的错误是使每个提供者都是通用的 - 因为它只接受一种类型(每种具体),而base是通用的。就像上面那样。通常,通用也会在每个界面受到限制,您可以在哪里/哪里 但是你有一个问题,因为从一个有效的非泛型类中回退到泛型上下文并不是直接的(同时考虑到有值类型的警告,因为你必须经常有时区别对待),反之亦然好。
因此,你首先需要像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>>();

希望这有助于一些......

答案 1 :(得分: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
}

答案 2 :(得分: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)
    {
         ....
    }
}

答案 3 :(得分: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");

答案 4 :(得分: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
Imo,这种方法比反射方法更差。很容易忘记将来的一些枚举。


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

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

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

  3. 将您的基类重命名为Aggregate<T>AggregateBase<T>。再次,“抽象”使其更多地涉及实施,非常不必要。