Eine Sache tun, die möglicherweise klar ist, ist, dass Ihr Design etwas fehlerhaft ist. Ein Switch-Typ ist nicht das Beste, was man in einer generischen Methode tun kann, die ihren Zweck vereitelt. Aber was nicht klar ist, ist der Zweck Ihrer Klassen.
Einige Spekulationen:
1) Ihr Paar Klassen sehen AskItem
und AskTankTruckAggregate<T>
usw. Ich denke nicht, letztere eine generische Klasse zu sein hat, ist es eine sehr spezielle Klasse, eng gekoppelt an AskItem
. Ich würde es neu zu gestalten wie
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
}
Nennen Sie es mögen:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
2) Eine andere Möglichkeit: delegieren die aggregierte Schaffung Auftrag an Ihren 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
}
Nennen Sie es mögen:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
3) oder gleich sein, aber machen es ein bisschen stark typisierte, mit der Verwendung von Generika:
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
}
Anruf es mag:
AbstractAggregateFactory.GetAggregateClient<AskItem>(); //etc
4) Schließlich kann der Rückgabetyp weniger generisch sein? Bezieht Schalterkasten mit ein, ich mag es nicht.
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
}
Nennen Sie es mögen:
AbstractAggregateFactory.GetAggregateClient(AggregateTypes.AskTankTruck); //etc
Imo ist dieser Ansatz schlechter als die Reflexion Ansatz. Es ist leicht zu vergessen, einige Enum Überprüfung in der Zukunft.
Von allen, 3. sieht das Beste für meine Augen, aber wieder ohne zu wissen, Ihr Design Ziel ist es sehr schwer vorherzusagen. Einige Vorschläge:
Ihr Fabrikname klingt besser wie AggregateFactory
. "Abstrakt" macht es mehr über die Implementierung.
Falls Sie eine Aufzählung benötigen, um den Typ zu bezeichnen, machen Sie ihn nicht verschachtelt. Verschachtelte öffentliche Typen sind schwieriger zu rufen. Entnehmen Sie die statische Klasse (wie in meinem 5. Ansatz).
Benennen Sie Ihre Basisklasse als Aggregate<T>
oder um. Nochmals "abstrakt" macht es mehr um Umsetzung, ganz unnötig.
danke für die detaillierte Erklärung. Ich habe ursprünglich eine andere Antwort gewählt, aber Sie haben mich überzeugt. Danke für die Hilfe! – apexdodge
np :) - es gibt viele Möglichkeiten/Antworten, bleibe einfach dabei, es logisch zu halten (jedes Bit hat normalerweise seinen Zweck oder gibt keinen Platz) und dir wird es gut gehen. Und schau dir IOC, Autofac an, das wird dir gefallen (mehr als Generika :) – NSGaga