Una cosa que es posiblemente claro es que su diseño es bastante imperfecto. Un tipo de cambio no es lo mejor que se puede hacer en un método genérico que anula su propósito. Pero lo que no está claro es cuál es el propósito de tus clases.
Algunas especulaciones:
1) ver a sus clases par AskItem
y AskTankTruckAggregate<T>
etc no creo que este último tiene que ser una clase genérica, es una clase muy específica, estrechamente unida a AskItem
. Me rediseñarlo como
public static class AbstractAggregateFactory
{
public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem
{
//use reflection to find the type that inherits AbstractAggregate<T>
//instantiate the type
//cast to AbstractAggregate<T> and return
}
}
public class AskTankTruckAggregate : AbstractAggregate<AskItem>
{
//not implemented yet
}
public class TankTruckBlogAggregate : AbstractAggregate<BlogItem>
{
//not implemented yet
}
public class ResourcesAggregate : AbstractAggregate<ResourceItem>
{
//not implemented yet
}
llamar así:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
2) Otra forma: delegar la creación de empleo agregado a sus ListItems.
public abstract class ListItem //or interface
{
protected abstract object Create();
}
public class AskItem : ListItem { //implement to return AskTankTruckAggregate
}
public class BlogItem : ListItem { //implement to return TankTruckBlogAggregate
}
public class ResourceItem : ListItem { //implement to return ResourcesAggregate
}
public static class AbstractAggregateFactory
{
public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem, new()
{
return (AbstractAggregate<T>)new T().Create();
}
}
public class AskTankTruckAggregate : AbstractAggregate<AskItem>
{
//not implemented yet
}
public class TankTruckBlogAggregate : AbstractAggregate<BlogItem>
{
//not implemented yet
}
public class ResourcesAggregate : AbstractAggregate<ResourceItem>
{
//not implemented yet
}
llamar así:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
3) o de la misma, pero que sea un poco más inflexible de tipos, con el uso de los genéricos:
public abstract class ListItem<T> where T : ListItem<T> //or interface
{
protected abstract AbstractAggregate<T> Create();
}
public class AskItem : ListItem<AskItem> { //implement to return AskTankTruckAggregate
}
public class BlogItem : ListItem<BlogItem> { //implement to return TankTruckBlogAggregate
}
public class ResourceItem : ListItem<ResourceItem> { //implement to return ResourcesAggregate
}
public static class AbstractAggregateFactory
{
public static AbstractAggregate<T> GetAggregateClient<T>() where T : ListItem, new()
{
return new T().Create();
}
}
public class AskTankTruckAggregate : AbstractAggregate<AskItem>
{
//not implemented yet
}
public class TankTruckBlogAggregate : AbstractAggregate<BlogItem>
{
//not implemented yet
}
public class ResourcesAggregate : AbstractAggregate<ResourceItem>
{
//not implemented yet
}
Call es como:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
4) Por último, ¿puede hacer que el tipo de devolución sea menos genérico? Implica la caja del interruptor, no me gusta.
public enum AggregateTypes { TankTruckBlog, AskTankTruck, Resources }
public static class AbstractAggregateFactory
{
public static AbstractAggregate GetAggregateClient(AggregateTypes type)
{
switch (type)
{
case AggregateTypes.AskTankTruck:
return new AskTankTruckAggregate<AskItem>();
case AggregateTypes.TankTruckBlog:
return new TankTruckBlogAggregate<BlogItem>();
case AggregateTypes.Resources:
return new ResourcesAggregate<ResourceItem>();
default:
throw new AggregateDoesNotExistException();
}
}
}
public abstract class AbstractAggregate
{
}
public abstract class AbstractAggregate<T> : AbstractAggregate
{
}
//or change the definition to AskTankTruckAggregate : AbstractAggregate<AskItem>
public class AskTankTruckAggregate<T> : AbstractAggregate<T>
{
//not implemented yet
}
//or change the definition to TankTruckBlogAggregate : AbstractAggregate<BlogItem>
public class TankTruckBlogAggregate<T> : AbstractAggregate<T>
{
//not implemented yet
}
//or change the definition to ResourcesAggregate : AbstractAggregate<ResourceItem>
public class ResourcesAggregate<T> : AbstractAggregate<T>
{
//not implemented yet
}
llamar así:
AbstractAggregateFactory.GetAggregateClient(AggregateTypes.AskTankTruck); //etc
Imo, este enfoque es peor que el enfoque de la reflexión. Es fácil olvidar algunas verificaciones enum en el futuro.
De todos, el tercero parece el mejor para mí, pero de nuevo sin conocer su objetivo de diseño, es muy difícil de predecir. Algunas sugerencias:
Su nombre de fábrica suena mejor como AggregateFactory
. "Resumen" en él lo hace más acerca de la implementación.
En caso de que necesite un tipo de enumeración para denotar, no lo haga anidado. Los tipos públicos anidados son más difíciles de llamar. Elimine la clase estática de envoltura (como en mi 5º enfoque).
Cambie el nombre de su clase base como Aggregate<T>
o . Una vez más, "Resumen" lo hace más acerca de la implementación, bastante innecesario.
gracias por la explicación detallada. originalmente elegí una respuesta diferente, pero me convenciste. ¡gracias por la ayuda! – apexdodge
np :) - hay muchas formas/respuestas, simplemente mantenlo lógico (cada bit usualmente tiene su propósito o no garantiza un lugar) y estarás bien. Y eche un vistazo a IOC, autofac, le gustará eso (más que genéricos :) – NSGaga