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

ape*_*dge 9 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
}
Run Code Online (Sandbox Code Playgroud)

NSG*_*aga 4

编译器抱怨的问题是你有一个“开放”(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;
    }
}
Run Code Online (Sandbox Code Playgroud)

...这是一种实现。

基本上,使一切变得“通用”并不总是最好的方法。您必须有足够的理由或未知的“类型”才能使用。与仿制药一样,您也需要支付一定的价格。将泛型跨越到非泛型世界通常很棘手,如果您的类型无法通过用法等推断,则需要进行反射。

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

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

因此,您首先需要诸如强制转换(对象)之类的东西。

我宁愿在这里使用某种 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>>();
Run Code Online (Sandbox Code Playgroud)

希望这对一些人有帮助。