Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何创建类工厂来创建所需的派生类_C#_Inheritance_Nested Class_Class Factory - Fatal编程技术网

C# 如何创建类工厂来创建所需的派生类

C# 如何创建类工厂来创建所需的派生类,c#,inheritance,nested-class,class-factory,C#,Inheritance,Nested Class,Class Factory,我经常使用类工厂模式,其中类有一个私有构造函数和一个静态方法来创建类。这允许出现由于某种原因无法构造类,并且返回null的情况—非常方便 我希望能够将其扩展到工厂方法,该方法根据条件从派生类的层次结构创建特定的类。但是,我看不到隐藏派生类的构造函数以强制使用工厂方法的方法。如果工厂方法位于基类中,则它不再有权访问派生类的私有构造函数。在每个派生类中放置工厂方法并不起作用,因为必须事先知道所需的类型。如果类可以访问嵌套类的私有成员,则嵌套类可能是一种方法,但遗憾的是,嵌套类似乎可以访问封闭类的私有

我经常使用类工厂模式,其中类有一个私有构造函数和一个静态方法来创建类。这允许出现由于某种原因无法构造类,并且返回null的情况—非常方便

我希望能够将其扩展到工厂方法,该方法根据条件从派生类的层次结构创建特定的类。但是,我看不到隐藏派生类的构造函数以强制使用工厂方法的方法。如果工厂方法位于基类中,则它不再有权访问派生类的私有构造函数。在每个派生类中放置工厂方法并不起作用,因为必须事先知道所需的类型。如果类可以访问嵌套类的私有成员,则嵌套类可能是一种方法,但遗憾的是,嵌套类似乎可以访问封闭类的私有成员,而不是相反


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

不使用类本身内部的方法作为工厂,而是通过静态类(“工厂”)实现工厂模式,该静态类根据您编写的逻辑返回正确的实例。

有几种可能性,其中两种是:

  • 将所有这些类放在一个项目中,并使构造函数内部化。其他项目将无法调用这些构造函数,但该项目中的代码可以
  • 使这些类的构造函数
    受保护
    (而不是
    私有
    ),并在包含工厂方法的类中创建私有派生类。创建该私有类的实例并返回它
  • 第二个选项的示例:

    public static class AnimalFactory
    {
        public static Animal Create(int parameter)
        {
            switch(parameter)
            {
                case 0:
                    return new DogProxy();
                case 1:
                    return new CatProxy();
                default:
                    throw new ArgumentOutOfRangeException("parameter");
            }
        }
    
        private class DogProxy : Dog { }
    
        private class CatProxy : Cat { }
    }
    
    public abstract class Animal { }
    
    public class Dog : Animal
    {
        protected Dog() { }
    }
    
    public class Cat : Animal
    {
        protected Cat() { }
    }
    

    这是丹尼尔发布答案时我正在编写的示例代码。看起来它在做他建议的事情:

    public static class BaseFactory
    {
        public static Base Create(bool condition)
        {
            if (condition)
            {
                return Derived1.Create(1, "TEST");
            }
            else
            {
                return Derived2.Create(1, DateTime.Now);
            }
        }
    }
    
    public class Base
    {
        protected Base(int value)
        {
        }
    
        protected static Base Create(int value)
        {
            return new Base(value);
        }
    }
    
    public sealed class Derived1: Base
    {
        private Derived1(int value, string text): base(value)
        {
        }
    
        internal static Derived1 Create(int value, string text)
        {
            return new Derived1(value, text);
        }
    }
    
    public sealed class Derived2: Base
    {
        private Derived2(int value, DateTime time): base(value)
        {
        }
    
        internal static Derived2 Create(int value, DateTime time)
        {
            return new Derived2(value, time);
        }
    }
    
    [编辑]对于Daniel的第二个建议:

    public static class BaseFactory
    {
        public static Base Create(bool condition)
        {
            if (condition)
            {
                return new Derived1Creator(1, "TEST");
            }
            else
            {
                return new Derived2Creator(1, DateTime.Now);
            }
        }
    
        private sealed class Derived1Creator: Derived1
        {
            public Derived1Creator(int value, string text): base(value, text)
            {
            }
        }
    
        private sealed class Derived2Creator: Derived2
        {
            public Derived2Creator(int value, DateTime time): base(value, time)
            {
            }
        }
    }
    
    public class Base
    {
        protected Base(int value)
        {
        }
    
        protected static Base Create(int value)
        {
            return new Base(value);
        }
    }
    
    public class Derived1: Base
    {
        protected Derived1(int value, string text): base(value)
        {
        }
    
        protected static Derived1 Create(int value, string text)
        {
            return new Derived1(value, text);
        }
    }
    
    public class Derived2: Base
    {
        protected Derived2(int value, DateTime time): base(value)
        {
        }
    
        protected static Derived2 Create(int value, DateTime time)
        {
            return new Derived2(value, time);
        }
    }
    

    请注意,不幸的是,第二种方法意味着类无法密封。

    您可以在基类构造函数中拦截派生类型创建,并使用StackFrames检查调用方是否是您的工厂:

     protected Class1() //base class ctor
        {
            StackFrame[] stackFrames = new StackTrace().GetFrames(); 
            foreach (var frame in stackFrames)
            {
                //check caller and throw an exception if not satisfied
            }
        }
    

    这并不能解决问题,即“阻止用户通过
    new
    ”创建实例”。但我同意把建筑留给第三类。基类不应该知道从它派生的类。@DanielHilgarth你是对的,因为他应该将另一个项目中的类型作为内部类型分开,并通过接口公开它们。请重新阅读问题。我引述:“然而,我看不到隐藏派生类的构造函数以强制使用工厂方法的方法。”Daniel和Mathew。真聪明。它工作并满足所有要求。我喜欢。我只是不知道谁的答案被接受:-)@Dave:你必须自己决定。通常你会接受对你帮助最大的答案。如果有多个答案对你有帮助,你要么不接受,要么不接受你更喜欢的答案,要么先发布的答案。丹尼尔和马修。真聪明。它工作并满足所有要求。我喜欢。我只是不知道谁的答案被接受:-)马修,第一个代码不是我第一个选项的意思。正如我所说的,将构造函数
    设置为内部
    。你们用额外的工厂方法绕道并没有增加任何好处。是的,这很公平。它只是用来演示工厂方法的使用——尽管工厂方法在本例中非常简单,它不会隐藏任何东西。在一般情况下,它可以。@Dave:丹尼尔是第一个发布代码的人,所以如果其他因素相同,你应该勾选他的。:)