在 C# 中执行此通用抽象类的最佳方法是什么? [英] Best way to do this generic abstract class in c#?

查看:33
本文介绍了在 C# 中执行此通用抽象类的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道我做得不对,但我也知道有一种方法可以做到这一点.我正在尝试尽可能通用和抽象,否则我的代码会变得非常混乱.所以我在这里也使用了策略模式,即 GetAggregateClient() 方法.

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

这就是背景信息.

这里的问题是我希望 GetAbstractAggregate() 返回实现 AbstractAggregate 的客户端类之一的实例,并根据传入的枚举.但是,我无法返回 AbstractAggregate.编译器不会让我这样做,这是有道理的,因为 AbstractAggregateFactory 类不是泛型.

有人知道这样做的最佳方法吗?

非常感谢.

公共静态类 AggregateHelper{公共枚举 AggregateTypes { TankTruckBlog, AskTankTruck, Resources }}公共静态类 AbstractAggregateFactory{public static AbstractAggregate<T>GetAggregateClient(AggregateHelper.AggregateTypes 类型){开关(类型){案例 AggregateHelper.AggregateTypes.AskTankTruck:返回新的 AskTankTruckAggregate();案例 AggregateHelper.AggregateTypes.TankTruckBlog:返回新的 TankTruckBlogAggregate();案例 AggregateHelper.AggregateTypes.Resources:返回新的 ResourcesAggregate();默认:抛出新的 AggregateDoesNotExistException();}}}公共抽象类 AbstractAggregate;{公共摘要列表<T>GetAggregate(Guid[] 资源类型);公共抽象 T GetSingle(字符串友好名称);}公共类 AskTankTruckAggregate<T>: AbstractAggregate{//还没有实现}公共类 TankTruckBlogAggregate: AbstractAggregate{//还没有实现}公共类 ResourcesAggregate: AbstractAggregate{//还没有实现}

解决方案

编译器抱怨的问题是你有一个方法是开放"(T) - 你正在返回封闭的泛型(使用


即你必须返回一个 <T> - 你可以用方法来做到这一点 - 无论工厂不是通用的,方法仍然可以.

至于什么是最好的方法,这更像是一个设计问题,而且故事有点长.我不完全确定你想要实现什么(可能是一些背景故事,你可能有多少类型等)

首先,您的项目不应(一般来说,作为最佳实践或某些感觉良好"的因素)继承自 ListItem.使用你的其他一些基类,如果你需要一个集合,使用一个像 List 这样的通用基类,或者创建你自己的 IList 实现等.>

其次,您不需要使所有内容都通用.您的基本聚合器是通用的,但自定义类通常不是.例如:

抽象类ItemBase { }类 AskItem : ItemBase { }类 BlogItem : ItemBase { }类 ProvderA : ProviderBase{公共覆盖 AskItem Get(){抛出新的 NotImplementedException();}}类 ProvderB : ProviderBase{公共覆盖 BlogItem Get(){抛出新的 NotImplementedException();}}抽象类 ProviderBase其中 T : ItemBase{公共抽象 T Get();}课程计划{静态无效主(字符串 [] args){ProviderBaseprovider = GetProvider();var item = provider.Get();}静态 ProviderBaseGetProvider() 其中 T : ItemBase{if (typeof(T) == typeof(AskItem))返回 (ProviderBase)(object)new ProvderA();if (typeof(T) == typeof(BlogItem))返回 (ProviderBase)(object)new ProvderB();返回空;}}

...这是一种实现.

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

在我看来,使每个提供程序通用 (<T>) 是错误的,因为它只接受一种类型(每种具体),而 base 是通用的.所以像上面那样.通常通用也受每个接口的限制.

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

因此,您首先需要诸如 cast (object) 之类的东西.

我宁愿在这里使用某种 IOC 方法 - 例如看看 autofac(我没有关联,但我喜欢它的工作方式,不错的框架).在这种情况下,你会做这样的事情:

container.Register>(c=>new ProvderA());container.Register>(c => new ProvderB());//稍后再查询...ProviderBaseprovider = container.Resolve>();

希望这对一些人有所帮助.

I know I'm not doing this right, but I also know there is a way to do this. I'm trying to be as generic and abstract as possible, otherwise my code is going to get real messy. So I'm using strategy pattern here as well, which is the GetAggregateClient() method.

I want to have an abstract class called AbstractAggregate<T>, so that it uses generics. The generic type will be a series of data classes (BlogItem, ResourceItem, and AskItem), which all inherit from ListItem.

So that's the background info.

The problem here is that I want GetAbstractAggregate() to return an instance of one of the client classes that implements AbstractAggregate, with the type of item specified depending on the enum passed in. However, I cannot return an AbstractAggregate<T>. The compiler won't let me, and that makes sense since, since the AbstractAggregateFactory class is not a generic.

Does anyone know the best way to do this?

Thanks a lot.

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
}

解决方案

The problem the compiler complains about is that you have a method which is 'open' (T) - and you're returning closed generic (with <AskItem> etc.), concrete type really.
i.e. you have to return a <T> - and you can do that with the method - no matter if the factory is not generic, the method still can be.

As for what's the best way to do it, that's more of a design question, and a bit longer story. I'm not entirely sure what you're trying to achieve (maybe some background story, how many types you might have etc.)

First, your items shouldn't (generally speaking, as a best practice or some 'feels good' factor) inherit from ListItem. Use some other base class of yours, and if you need a collection, use a generic one like List<T>, or create your own IList implementation, etc.

Second, you don't need to make everything generic. Your base aggregator is generic but custom classes are not, usually. For example:

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;
    }
}

...that's one implementation.

Basically, making everything 'generic' is not always the best way. You have to have enough reasons or 'types' unknown to be possibly used. As with generic you also pay a certain price. Crossing generics to non-generics world is often tricky, and involves reflection if your types can't be inferred by the usage etc.

In my opinion, it's a mistake making each provider generic (<T>), as it only accepts one type (each concrete), while base is generic. So like the above. Usually generic is also constrained per interface where/where you can.

But then you have a problem, as casting back to generic context from effectively a non-generic class is not straight (also have in mind there are caveats with value types as you often have to treat that differently), and vice versa as well.

Hence you need something like cast (object) first.

I'd rather use sort of an IOC approach here - e.g. look at the autofac (I'm not associated but I like how it works, nice framework). In that case you'd do something like this:

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

// and query later...

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

Hope this helps some.

这篇关于在 C# 中执行此通用抽象类的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆