c# - 在 C# 中执行此通用抽象类的最佳方法?

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

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

我想要一个名为 AbstractAggregate<T> 的抽象类,以便它使用泛型。通用类型将是一系列数据类( BlogItemResourceItemAskItem ),它们都继承自 ListItem .

这就是背景信息。

这里的问题是我想要GetAbstractAggregate()返回实现 AbstractAggregate 的客户端类之一的实例,根据传入的枚举指定项目类型。但是,我无法返回 AbstractAggregate<T> .编译器不会让我这样做,这是有道理的,因为 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
}

最佳答案

编译器提示的问题是你有一个“开放”(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;
    }
}

...这是一个实现。

基本上,使所有内容都“通用”并不总是最好的方法。您必须有足够的理由或未知的“类型”才能被使用。与泛型一样,您也需要付出一定的代价。将泛型转换到非泛型世界通常很棘手,如果您的类型无法通过用法等推断出来,则涉及反射。

在我看来,让每个提供者都通用(<T>)是错误的,因为它只接受一种类型(每个具体的),而基础是通用的。所以就像上面那样。通常泛型也受到每个接口(interface)的限制。

但是你会遇到一个问题,因为从一个非泛型类有效地转换回泛型上下文并不是直接的(同时要记住,值类型有一些警告,因为你经常必须以不同的方式对待它),反之亦然以及。

因此你首先需要像 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>>();

希望这对一些人有帮助。

关于c# - 在 C# 中执行此通用抽象类的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9949406/

相关文章:

java - Eclipse方法调用重构

c# - 使用 linq 从链接到另一个表的表中获取单个记录

c# - 读取双嵌套 xml

java - 不兼容的类型,但没有意义(Java)

java - 泛型 <? super A> 不允许将 A 的父类(super class)型添加到列表中

c# - 在 VS2008 中用花括号 {} 包围代码块的任何方法?

Java:重构嵌套循环

c# - 如何在类级别从 PropertyInfo 获取 DataContract 属性?

c# - 内存流与文件流 : Document Viewer rendering document from filestream successfully but not memorystream?

typescript - 过滤通用类型