在C#中完成此通用抽象类的最佳方法?

问题描述 投票:9回答:5

我知道我没有正确执行此操作,但是我也知道有一种方法可以执行此操作。我正在尝试尽可能地通用和抽象,否则我的代码将变得混乱不堪。所以我也在这里使用策略模式,这是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
}
c# generics refactoring abstract-class strategy-pattern
5个回答
3
投票

问题,编译器抱怨...就是您有一个'open'(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(对象)这样的东西。我宁愿在这里使用某种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
投票

我正在尝试尽可能地通用和抽象,否则我的代码将变得混乱不堪。


1
投票

怎么样:


0
投票

[可能]清楚的一件事是您的设计有些缺陷。在违反通用方法的通用方法中,打开类型并不是最好的选择。但是尚不清楚您的课程的目的是什么。

© www.soinside.com 2019 - 2024. All rights reserved.