2008-08-21 11 views
5

Ich habe eine Sammlung von Klassen, die von einer abstrakten Klasse erben, die ich erstellt habe. Ich möchte die abstrakte Klasse als eine Factory zum Erstellen von Instanzen von konkreten Implementierungen meiner abstrakten Klasse verwenden.Gibt es eine Möglichkeit, einen Konstruktor nur für eine Elternklasse in C# sichtbar zu machen?

Gibt es eine Möglichkeit, einen Konstruktor von allem Code außer einer Elternklasse zu verbergen.

Ich möchte diese im Grunde

public abstract class AbstractClass 
{ 
    public static AbstractClass MakeAbstractClass(string args) 
    { 
     if (args == "a") 
      return new ConcreteClassA(); 
     if (args == "b") 
      return new ConcreteClassB(); 
    } 
} 

public class ConcreteClassA : AbstractClass 
{ 
} 

public class ConcreteClassB : AbstractClass 
{ 
} 

tun, aber ich will niemanden verhindern, dass direkt die zwei konkrete Klassen instanziieren. Ich möchte sicherstellen, dass nur die MakeAbstractClass() -Methode die Basisklassen instanziieren kann. Gibt es eine Möglichkeit, dies zu tun?

UPDATE
Ich brauche nicht von außerhalb der abstrakten Klasse keine spezifischen Methoden der ConcreteClassA oder B zuzugreifen. Ich brauche nur die öffentlichen Methoden, die meine Abstract-Klasse bietet. Ich muss nicht wirklich verhindern, dass die Concrete-Klassen instanziiert werden, ich versuche nur, sie zu vermeiden, da sie keine neuen öffentlichen Schnittstellen bereitstellen, sondern nur verschiedene Implementierungen einiger ganz spezieller Dinge, die innerhalb der abstrakten Klasse liegen.

Für mich ist die einfachste Lösung make child classes as samjudson mentioned. Ich möchte das jedoch vermeiden, da es die Datei meiner abstrakten Klasse viel größer machen würde, als ich es gerne hätte. Ich möchte lieber, dass Klassen für die Organisation über einige Dateien verteilt werden.

Ich denke, es gibt keine einfache Lösung für dieses ...

Antwort

2

Sie können die Klassen Unterklassen Kind machen, etwa so:

public abstract class AbstractClass 
{ 
    public static AbstractClass MakeAbstractClass(string args) 
    { 
     if (args == "a") 
      return new ConcreteClassA(); 
     if (args == "b") 
      return new ConcreteClassB(); 
    } 

    private class ConcreteClassA : AbstractClass 
    { 
    } 

    private class ConcreteClassB : AbstractClass 
    { 
    } 
} 

@Vaibhav Dies bedeutet in der Tat, dass die Klassen auch versteckt sind. Aber soweit ich weiß, ist dies der einzige Weg, den Konstruktor vollständig zu verbergen.

Edit: Wie andere bereits erwähnt haben, kann das Gleiche mit Reflection erreicht werden, was vielleicht näher an dem liegt, was Sie gerne hätten - zum Beispiel antwortet die obige Methode auf die konkreten Klassen, die sich in derselben Datei befinden die abstrakte Klasse, die wahrscheinlich nicht sehr praktisch ist. Allerdings ist dieser Weg ein netter "Hack" und gut, wenn die Anzahl und Komplexität der konkreten Klassen gering ist.

+0

Schönes Beispiel, aber machen Sie die Benennung ein bisschen mehr NETy und nennen Sie es "CreateAbstractClass (string args)" für Coding-Standards Willen :) –

1

Nein, ich glaube nicht, dass wir das tun können.

3

Wenn die Klassen in derselben Baugruppe sind, können Sie die Konstruktoren nicht intern machen?

0

Haben Sie eigentlich müssen dies tun? Wenn Sie eine Art Pseudo-Factory-Muster verwenden, ohne dafür ein echtes Design zu benötigen, wird Ihr Code nur schwer verständlich, zu pflegen und zu erweitern sein.

Wenn Sie dies nicht tun müssen, implementieren Sie einfach ein echtes Factory-Muster. Oder, mehr ALTy, verwenden Sie ein DI/IoC-Framework.

6

Für mich ist die einfachste Lösung ist es, make Kind Klassen als samjudson erwähnt. Ich möchte dieses jedoch vermeiden, da es meine abstrakte Klassenakte viel größer als machen würde, würde ich es mögen.Ich würde lieber Klassen aufgeteilt über ein paar Dateien für Organisation.

Kein Problem, verwenden Sie einfach Teil Stichwort und Sie können Ihre innere Klassen in so viele Dateien aufgeteilt, wie Sie wollen. Sie müssen es nicht in derselben Datei speichern.

Zurück Antwort:

es möglich ist, aber nur mit Reflexion

public abstract class AbstractClass 
{ 
    public static AbstractClass MakeAbstractClass(string args) 
    { 
     if (args == "a") 
      return (AbstractClass)Activator.CreateInstance(typeof(ConcreteClassA), true); 
     if (args == "b") 
      return (AbstractClass)Activator.CreateInstance(typeof(ConcreteClassB), true); 
    } 
} 

public class ConcreteClassA : AbstractClass 
{ 
    private ConcreteClassA() 
    { 
    } 
} 

public class ConcreteClassB : AbstractClass 
{ 
    private ConcreteClassB() 
    { 
    } 
} 

und hier ist ein weiteres Muster, ohne hässliche MakeAbstractClass (string args)

public abstract class AbstractClass<T> where T : AbstractClass<T> 
{ 
    public static T MakeAbstractClass() 
    { 
     T value = (T)Activator.CreateInstance(typeof(T), true); 
     // your processing logic 
     return value; 
    } 
} 

public class ConcreteClassA : AbstractClass<ConcreteClassA> 
{ 
    private ConcreteClassA() 
    { 
    } 
} 

public class ConcreteClassB : AbstractClass<ConcreteClassB> 
{ 
    private ConcreteClassB() 
    { 
    } 
} 
-2

Was Sie Sie müssen dies tun, um zu verhindern, dass der Standardkonstruktor erstellt wird. Die interne Variable kann in public geändert werden, wenn sich die Klassen nicht in derselben Assembly befinden.

public abstract class AbstractClass{ 

public static AbstractClass MakeAbstractClass(string args) 
{ 
    if (args == "a") 
     return ConcreteClassA().GetConcreteClassA(); 
    if (args == "b") 
     return ConcreteClassB().GetConcreteClassB(); 
} 
} 

public class ConcreteClassA : AbstractClass 
{ 
    private ConcreteClassA(){} 

    internal static ConcreteClassA GetConcreteClassA(){ 
     return ConcreteClassA(); 
    } 
} 

public class ConcreteClassB : AbstractClass 
{ 
    private ConcreteClassB(){} 
    internal static ConcreteClassB Get ConcreteClassB(){ 
     return ConcreteClassB(); 
    } 

} 
0

Können Sie nicht das Schlüsselwort partial für den Code für eine Klasse in viele Dateien aufteilen?

0

Wenn Sie diese Klasse in einer separaten Serviceassembly verwenden, können Sie das interne Schlüsselwort verwenden.

public class AbstractClass 
{ 
    public AbstractClass ClassFactory(string args) 
    { 
     switch (args) 
     { 
      case "A": 
       return new ConcreteClassA();    
      case "B": 
       return new ConcreteClassB();    
      default: 
       return null; 
     } 
    } 
} 

public class ConcreteClassA : AbstractClass 
{ 
    internal ConcreteClassA(){ } 
} 

public class ConcreteClassB : AbstractClass 
{ 
    internal ConcreteClassB() {} 
} 
1

Im Anschluss an die accepted answer, wenn Sie eine öffentliche Schnittstelle hatte und machte die privaten Klassen die Schnittstelle implementieren, können Sie dann einen Zeiger auf die Schnittstelle und jemand außerhalb Ihrer Eltern könnten abstrakte Klasse sie dann verwenden (während immer noch die Kinder Klassen versteckt).