做在C#这个通用抽象类的最佳方式? [英] Best way to do this generic abstract class in c#?

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

问题描述

我知道我不是这样做的权利,但我也知道有一个办法做到这一点。我想作为通用和抽象越好,否则,我的代码是会得到真正的混乱。所以我在这里使用的地狱战略格局这是GetAggregateClient()方法。



我想有一个叫AbstractAggregate抽象类,以便它使用泛型。将要使用的类型是一系列它们BlogItem,ResourceItem和AskItem数据类。这些数据类都是从列表项继承。



这就是背景信息。这里的问题是,我想GetAbstractAggregate()返回,随着项目的类型实现AbstractAggregate客户端类的一个实例指定根据传入的枚举,但我不能返回AbstractAggregate。编译器不会让我,这是有道理的,因为自从AbstractAggregateFactory类不是一般的。



有没有人有这样做的最佳方式?



非常感谢。

 公共静态类AggregateHelper 
{
酒店的公共枚举AggregateTypes {TankTruckBlog,AskTankTruck,资源}
}

公共静态类AbstractAggregateFactory
{
公共静态AbstractAggregate< T> GetAggregateClient(AggregateHelper.AggregateTypes型)
{
开关(类型)
{
情况下AggregateHelper.AggregateTypes.AskTankTruck:
返回新AskTankTruckAggregate< AskItem>();
情况下AggregateHelper.AggregateTypes.TankTruckBlog:
返回新TankTruckBlogAggregate< BlogItem>();
情况下AggregateHelper.AggregateTypes.Resources:
返回新ResourcesAggregate< ResourceItem>();
默认:
抛出新AggregateDoesNotExistException();
}
}
}

公共抽象类AbstractAggregate< T>
{
公共抽象列表< T> GetAggregate(GUID [] resourcetypes);

公共抽象牛逼GetSingle(字符串的FriendlyName);


}

公共类AskTankTruckAggregate< T> :AbstractAggregate< T>
{
//尚未实现
}

公共类TankTruckBlogAggregate< T> :AbstractAggregate< T>
{
//尚未实现
}

公共类ResourcesAggregate< T> :AbstractAggregate< T>
{
//尚未实现
}


解决方案

这个问题,编译器会抱怨结果
...是,你必须是开放(T)的方法 - 而你归国关闭通用(含< AskItem方式> 等),具体型号真的结果
即你必须返回一个... < T> - ...你可以做到这一点的方法 - 无论工厂不通用的,方法可能还是结果
至于什么是做到这一点的最好办法,结果
,这是一个设计问题多 - 的时间长一点的故事,结果
我不能完全确定你想实现(也许有些故事背景,有多少种什么你可能有等)



首先,你不应该(一般来说,作为最佳做法,或者一些感觉良好的因素),结果
从列表项继承你的项目 - 使用一些其他的基类你的 - 如果你需要一个集合使用一个通用的一个像列表< T> - 或创建自己的IList实现等等。



二,事情是,你并不需要的一切通用的。你的基地聚合器是通用的,但自定义类都没有,通常情况下,例如像这样...

 抽象类ItemBase {} 
类AskItem:ItemBase {}
类BlogItem :ItemBase {}
类ProvderA:&的ProviderBase LT; AskItem>
{
公众覆盖AskItem的get()
{
抛出新NotImplementedException();
}
}
类ProvderB:&的ProviderBase LT; BlogItem>
{
公众覆盖BlogItem获得()
{
抛出新NotImplementedException();
}
}
抽象类的ProviderBase< T>其中T:ItemBase
{
公共抽象吨得到();
}
类节目
{
静态无效的主要(字串[] args)
{
的ProviderBase< AskItem>供应商= GetProvider< AskItem>();
VAR项目= provider.Get();
}
静态的ProviderBase< T> GetProvider< T>()其中T:ItemBase
{
如果(typeof运算(T)== typeof运算(AskItem))
回报率(的ProviderBase< T>)(对象)新ProvderA() ;
如果(typeof运算(T)== typeof运算(BlogItem))
回报率(的ProviderBase< T>)(对象)新ProvderB();
返回NULL;
}
}



...这是一个实现。结果
基本上不是万能的通用永远是最好的方法。你必须有足够的理由或将可能使用'类型'未知。正如通用也付出一定的代价。穿越仿制药向非泛型的世界往往是棘手的,并且涉及反射,如果你的类型不能等结果
IMO的错误是使每一个供应商一个通用的使用推断 - 因为它只接受一种类型(每个具体的),而基础是通用的。因此,像上面。通常一般也每个接口的地方/在这里你可以。结果
但是你有一个问题,因为从有效的非泛型类转换回一般上下文是不是直的(也有心中有约束值类型警告你有来治疗不同,有时,经常),反之也是如此。结果
因此,你需要像投(对象)第一。结果
我想而使用国际奥委会的排序方法的位置 - 如看 autofac (我没有关联,但我喜欢它是如何工作的,好的框架) 。在这种情况下,你会做这样的事情...

  container.Register<的ProviderBase< AskItem>>(C => ;新ProvderA()); 
container.Register<&的ProviderBase LT; BlogItem>>(C =>新建ProvderB());

//和查询后...

的ProviderBase< AskItem>供应商= container.Resolve<&的ProviderBase LT; AskItem>>();



希望这有助于一些...


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 hell which is the GetAggregateClient() method.

I want to have an abstract class called AbstractAggregate, so that it uses generics. The type that will be used are a series of data classes which are BlogItem, ResourceItem, and AskItem. These data classes 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". Compiler won't let me and that makes sense since since the AbstractAggregateFactory class is not a generic.

Does anyone have 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, 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, method can be still.
As for what's the best way to do it,
that's a 'design' question more - and a bit longer story,
I'm not entirely sure what you're trying to achieve (maybe some background story, how much types you might have etc.),

First, you shouldn't (generally speaking, as a best practice or some 'feels good' factor)
inherit your items 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, thing is that you don't need everything generic. Your base aggregator is generic but custom classes are not, usually, e.g. like this...

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, not everything 'generic' is 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.
IMO mistake is making each provider a generic - 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 an effectively a non-generic class is not straight (also have in mind there are caveats with value types as you have to treat that differently sometimes, often), and vice versa as well.
Hence you need something like cast (object) first.
I'd rather use sort of 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 ...

        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天全站免登陆