C# 当创建基于运行时传递的信息时,如何在工厂方法中去掉switch语句

C# 当创建基于运行时传递的信息时,如何在工厂方法中去掉switch语句,c#,xml,factory,C#,Xml,Factory,我目前正在努力在我的解决方案中创建一个好的类工厂。 我正在创建一个能够处理非常精确的XML文档的模型。 我有一个抽象类“TreeElement”,它实现了共享功能,并且有许多子类继承自它。 目前,我被一个工厂方法绊倒了,它包含一个我想去掉的大switch语句,但我不知道如何做到这一点 主要的问题是,我不知道在运行时之前应该使用什么子类,因为信息在XMLNode的后代中,我必须首先从中读取 如何解决这个问题,使其看起来不会是这样: public ITreeElement CreateProperT

我目前正在努力在我的解决方案中创建一个好的类工厂。

我正在创建一个能够处理非常精确的XML文档的模型。
我有一个抽象类“TreeElement”,它实现了共享功能,并且有许多子类继承自它。

目前,我被一个工厂方法绊倒了,它包含一个我想去掉的大switch语句,但我不知道如何做到这一点

主要的问题是,我不知道在运行时之前应该使用什么子类,因为信息在XMLNode的后代中,我必须首先从中读取

如何解决这个问题,使其看起来不会是这样:

public ITreeElement CreateProperType(...)
{
        switch (nodeType)
        {
            case "A":
               return new A();
            case "B":
               return new B();
            ...
        }
}

如您的示例所示,如果节点类型始终是类名,则可以使用
Activator

return (ITreeElement)Activator.CreateInstance ("AssemblyName","MyNamespace." + nodeType);

如您的示例所示,如果节点类型始终是类名,则可以使用
Activator

return (ITreeElement)Activator.CreateInstance ("AssemblyName","MyNamespace." + nodeType);

您可以为每个ITreeElement类型创建一个类,该类可以告诉工厂它可以处理哪个节点类型,也可以创建类型。像这样的

interface ITreeElementCreator
{
    string HandlesNodeType { get; }
    ITreeElement CreateTreeElement();
}
class ACreator : ITreeElementCreator
{
    public string HandlesNodeType => "A";

    public ITreeElement CreateTreeElement()
    {
        return new A();
    }
}

class BCreator : ITreeElementCreator
{
    public string HandlesNodeType => "B";

    public ITreeElement CreateTreeElement()
    {
        return new B();
    }
}
class TreeElementFactory
{
    private readonly IEnumerable<ITreeElementCreator> treeElementCreators;

    public TreeElementFactory(IEnumerable<ITreeElementCreator> treeElementCreators)
    {
        this.treeElementCreators = treeElementCreators;
    }

    public ITreeElement CreateProperType(string nodeType)
    {
        return treeElementCreators.SingleOrDefault(te => te.HandlesNodeType == nodeType).CreateTreeElement() ?? throw new ArgumentException($"Unknown nodeType {nodeType}");
    }
}
class TreeElementFactory
{
    private static Dictionary<string, Func<ITreeElement>> creatorFuncs = new Dictionary<string, Func<ITreeElement>>
    {
        { "A", () => new A() },
        { "B", () => new B() }
    };

    public static ITreeElement CreateProperType(string nodeType)
    {
        if (!creatorFuncs.TryGetValue(nodeType, out var creatorFunc))
            throw new ArgumentException($"Unknown nodetype {nodeType}");
        return creatorFunc();
    }
}
然后你可以像这样为A和B实现一个

interface ITreeElementCreator
{
    string HandlesNodeType { get; }
    ITreeElement CreateTreeElement();
}
class ACreator : ITreeElementCreator
{
    public string HandlesNodeType => "A";

    public ITreeElement CreateTreeElement()
    {
        return new A();
    }
}

class BCreator : ITreeElementCreator
{
    public string HandlesNodeType => "B";

    public ITreeElement CreateTreeElement()
    {
        return new B();
    }
}
class TreeElementFactory
{
    private readonly IEnumerable<ITreeElementCreator> treeElementCreators;

    public TreeElementFactory(IEnumerable<ITreeElementCreator> treeElementCreators)
    {
        this.treeElementCreators = treeElementCreators;
    }

    public ITreeElement CreateProperType(string nodeType)
    {
        return treeElementCreators.SingleOrDefault(te => te.HandlesNodeType == nodeType).CreateTreeElement() ?? throw new ArgumentException($"Unknown nodeType {nodeType}");
    }
}
class TreeElementFactory
{
    private static Dictionary<string, Func<ITreeElement>> creatorFuncs = new Dictionary<string, Func<ITreeElement>>
    {
        { "A", () => new A() },
        { "B", () => new B() }
    };

    public static ITreeElement CreateProperType(string nodeType)
    {
        if (!creatorFuncs.TryGetValue(nodeType, out var creatorFunc))
            throw new ArgumentException($"Unknown nodetype {nodeType}");
        return creatorFunc();
    }
}
然后,您可以让您的工厂从IoC容器中获取所有
ITreeElementCreator
实现的列表,然后它可以找到正确的创建者,并要求它像这样为您提供
ITreeElement

interface ITreeElementCreator
{
    string HandlesNodeType { get; }
    ITreeElement CreateTreeElement();
}
class ACreator : ITreeElementCreator
{
    public string HandlesNodeType => "A";

    public ITreeElement CreateTreeElement()
    {
        return new A();
    }
}

class BCreator : ITreeElementCreator
{
    public string HandlesNodeType => "B";

    public ITreeElement CreateTreeElement()
    {
        return new B();
    }
}
class TreeElementFactory
{
    private readonly IEnumerable<ITreeElementCreator> treeElementCreators;

    public TreeElementFactory(IEnumerable<ITreeElementCreator> treeElementCreators)
    {
        this.treeElementCreators = treeElementCreators;
    }

    public ITreeElement CreateProperType(string nodeType)
    {
        return treeElementCreators.SingleOrDefault(te => te.HandlesNodeType == nodeType).CreateTreeElement() ?? throw new ArgumentException($"Unknown nodeType {nodeType}");
    }
}
class TreeElementFactory
{
    private static Dictionary<string, Func<ITreeElement>> creatorFuncs = new Dictionary<string, Func<ITreeElement>>
    {
        { "A", () => new A() },
        { "B", () => new B() }
    };

    public static ITreeElement CreateProperType(string nodeType)
    {
        if (!creatorFuncs.TryGetValue(nodeType, out var creatorFunc))
            throw new ArgumentException($"Unknown nodetype {nodeType}");
        return creatorFunc();
    }
}
类树元素工厂
{
私有只读IEnumerable树元素创建者;
公共TreeElementFactory(IEnumerable treeElementCreators)
{
this.treeElementCreators=treeElementCreators;
}
公共ITreeElement CreatePropertyType(字符串节点类型)
{
返回treeElementCreators.SingleOrDefault(te=>te.HandlesNodeType==nodeType).CreateTreeElement()??抛出新的ArgumentException($“未知nodeType{nodeType}”);
}
}

这样做的好处是,您可以在不更改工厂的情况下添加新类型的
ITreeElement

您可以为每个ITreeElement类型创建一个类,该类可以告诉工厂它可以处理哪个节点类型,也可以创建类型。像这样的

interface ITreeElementCreator
{
    string HandlesNodeType { get; }
    ITreeElement CreateTreeElement();
}
class ACreator : ITreeElementCreator
{
    public string HandlesNodeType => "A";

    public ITreeElement CreateTreeElement()
    {
        return new A();
    }
}

class BCreator : ITreeElementCreator
{
    public string HandlesNodeType => "B";

    public ITreeElement CreateTreeElement()
    {
        return new B();
    }
}
class TreeElementFactory
{
    private readonly IEnumerable<ITreeElementCreator> treeElementCreators;

    public TreeElementFactory(IEnumerable<ITreeElementCreator> treeElementCreators)
    {
        this.treeElementCreators = treeElementCreators;
    }

    public ITreeElement CreateProperType(string nodeType)
    {
        return treeElementCreators.SingleOrDefault(te => te.HandlesNodeType == nodeType).CreateTreeElement() ?? throw new ArgumentException($"Unknown nodeType {nodeType}");
    }
}
class TreeElementFactory
{
    private static Dictionary<string, Func<ITreeElement>> creatorFuncs = new Dictionary<string, Func<ITreeElement>>
    {
        { "A", () => new A() },
        { "B", () => new B() }
    };

    public static ITreeElement CreateProperType(string nodeType)
    {
        if (!creatorFuncs.TryGetValue(nodeType, out var creatorFunc))
            throw new ArgumentException($"Unknown nodetype {nodeType}");
        return creatorFunc();
    }
}
然后你可以像这样为A和B实现一个

interface ITreeElementCreator
{
    string HandlesNodeType { get; }
    ITreeElement CreateTreeElement();
}
class ACreator : ITreeElementCreator
{
    public string HandlesNodeType => "A";

    public ITreeElement CreateTreeElement()
    {
        return new A();
    }
}

class BCreator : ITreeElementCreator
{
    public string HandlesNodeType => "B";

    public ITreeElement CreateTreeElement()
    {
        return new B();
    }
}
class TreeElementFactory
{
    private readonly IEnumerable<ITreeElementCreator> treeElementCreators;

    public TreeElementFactory(IEnumerable<ITreeElementCreator> treeElementCreators)
    {
        this.treeElementCreators = treeElementCreators;
    }

    public ITreeElement CreateProperType(string nodeType)
    {
        return treeElementCreators.SingleOrDefault(te => te.HandlesNodeType == nodeType).CreateTreeElement() ?? throw new ArgumentException($"Unknown nodeType {nodeType}");
    }
}
class TreeElementFactory
{
    private static Dictionary<string, Func<ITreeElement>> creatorFuncs = new Dictionary<string, Func<ITreeElement>>
    {
        { "A", () => new A() },
        { "B", () => new B() }
    };

    public static ITreeElement CreateProperType(string nodeType)
    {
        if (!creatorFuncs.TryGetValue(nodeType, out var creatorFunc))
            throw new ArgumentException($"Unknown nodetype {nodeType}");
        return creatorFunc();
    }
}
然后,您可以让您的工厂从IoC容器中获取所有
ITreeElementCreator
实现的列表,然后它可以找到正确的创建者,并要求它像这样为您提供
ITreeElement

interface ITreeElementCreator
{
    string HandlesNodeType { get; }
    ITreeElement CreateTreeElement();
}
class ACreator : ITreeElementCreator
{
    public string HandlesNodeType => "A";

    public ITreeElement CreateTreeElement()
    {
        return new A();
    }
}

class BCreator : ITreeElementCreator
{
    public string HandlesNodeType => "B";

    public ITreeElement CreateTreeElement()
    {
        return new B();
    }
}
class TreeElementFactory
{
    private readonly IEnumerable<ITreeElementCreator> treeElementCreators;

    public TreeElementFactory(IEnumerable<ITreeElementCreator> treeElementCreators)
    {
        this.treeElementCreators = treeElementCreators;
    }

    public ITreeElement CreateProperType(string nodeType)
    {
        return treeElementCreators.SingleOrDefault(te => te.HandlesNodeType == nodeType).CreateTreeElement() ?? throw new ArgumentException($"Unknown nodeType {nodeType}");
    }
}
class TreeElementFactory
{
    private static Dictionary<string, Func<ITreeElement>> creatorFuncs = new Dictionary<string, Func<ITreeElement>>
    {
        { "A", () => new A() },
        { "B", () => new B() }
    };

    public static ITreeElement CreateProperType(string nodeType)
    {
        if (!creatorFuncs.TryGetValue(nodeType, out var creatorFunc))
            throw new ArgumentException($"Unknown nodetype {nodeType}");
        return creatorFunc();
    }
}
类树元素工厂
{
私有只读IEnumerable树元素创建者;
公共TreeElementFactory(IEnumerable treeElementCreators)
{
this.treeElementCreators=treeElementCreators;
}
公共ITreeElement CreatePropertyType(字符串节点类型)
{
返回treeElementCreators.SingleOrDefault(te=>te.HandlesNodeType==nodeType).CreateTreeElement()??抛出新的ArgumentException($“未知nodeType{nodeType}”);
}
}

这样做的好处是,您可以在不更改工厂的情况下添加新类型的
ITreeElement

一个简单的方法是使用节点类型字典和相应的函数来创建这样的类型

interface ITreeElementCreator
{
    string HandlesNodeType { get; }
    ITreeElement CreateTreeElement();
}
class ACreator : ITreeElementCreator
{
    public string HandlesNodeType => "A";

    public ITreeElement CreateTreeElement()
    {
        return new A();
    }
}

class BCreator : ITreeElementCreator
{
    public string HandlesNodeType => "B";

    public ITreeElement CreateTreeElement()
    {
        return new B();
    }
}
class TreeElementFactory
{
    private readonly IEnumerable<ITreeElementCreator> treeElementCreators;

    public TreeElementFactory(IEnumerable<ITreeElementCreator> treeElementCreators)
    {
        this.treeElementCreators = treeElementCreators;
    }

    public ITreeElement CreateProperType(string nodeType)
    {
        return treeElementCreators.SingleOrDefault(te => te.HandlesNodeType == nodeType).CreateTreeElement() ?? throw new ArgumentException($"Unknown nodeType {nodeType}");
    }
}
class TreeElementFactory
{
    private static Dictionary<string, Func<ITreeElement>> creatorFuncs = new Dictionary<string, Func<ITreeElement>>
    {
        { "A", () => new A() },
        { "B", () => new B() }
    };

    public static ITreeElement CreateProperType(string nodeType)
    {
        if (!creatorFuncs.TryGetValue(nodeType, out var creatorFunc))
            throw new ArgumentException($"Unknown nodetype {nodeType}");
        return creatorFunc();
    }
}
类树元素工厂
{
私有静态字典creatorFuncs=新字典
{
{“A”,()=>新的A()},
{“B”,()=>新的B()}
};
公共静态ITreeElement CreatePropertyType(字符串节点类型)
{
if(!creatorFuncs.TryGetValue(节点类型,out变量creatorFunc))
抛出新ArgumentException($“未知节点类型{nodetype}”);
返回creatorFunc();
}
}

一个简单的方法是使用节点类型字典和相应的函数来创建这样的类型

interface ITreeElementCreator
{
    string HandlesNodeType { get; }
    ITreeElement CreateTreeElement();
}
class ACreator : ITreeElementCreator
{
    public string HandlesNodeType => "A";

    public ITreeElement CreateTreeElement()
    {
        return new A();
    }
}

class BCreator : ITreeElementCreator
{
    public string HandlesNodeType => "B";

    public ITreeElement CreateTreeElement()
    {
        return new B();
    }
}
class TreeElementFactory
{
    private readonly IEnumerable<ITreeElementCreator> treeElementCreators;

    public TreeElementFactory(IEnumerable<ITreeElementCreator> treeElementCreators)
    {
        this.treeElementCreators = treeElementCreators;
    }

    public ITreeElement CreateProperType(string nodeType)
    {
        return treeElementCreators.SingleOrDefault(te => te.HandlesNodeType == nodeType).CreateTreeElement() ?? throw new ArgumentException($"Unknown nodeType {nodeType}");
    }
}
class TreeElementFactory
{
    private static Dictionary<string, Func<ITreeElement>> creatorFuncs = new Dictionary<string, Func<ITreeElement>>
    {
        { "A", () => new A() },
        { "B", () => new B() }
    };

    public static ITreeElement CreateProperType(string nodeType)
    {
        if (!creatorFuncs.TryGetValue(nodeType, out var creatorFunc))
            throw new ArgumentException($"Unknown nodetype {nodeType}");
        return creatorFunc();
    }
}
类树元素工厂
{
私有静态字典creatorFuncs=新字典
{
{“A”,()=>新的A()},
{“B”,()=>新的B()}
};
公共静态ITreeElement CreatePropertyType(字符串节点类型)
{
if(!creatorFuncs.TryGetValue(节点类型,out变量creatorFunc))
抛出新ArgumentException($“未知节点类型{nodetype}”);
返回creatorFunc();
}
}

我不知道,谢谢!不幸的是,大多数名称是匹配的,但并非所有名称都匹配。尽管如此,如果没有其他可能性,我认为在这个阶段我可以重构代码以完全匹配名称。我不知道,谢谢!不幸的是,大多数名称是匹配的,但并非所有名称都匹配。尽管如此,如果没有其他可能性,我认为在这一阶段我可以重构代码以完全匹配名称。还有其他一些选项可能会进一步抽象这一点,例如,在启动或构建工厂时加载字典,带有字符串键和某种工厂委托,或者只是一个类型等等,但是我认为switch语句并不是天生就坏的——我认为你的例子是一个很好的例子。你已经在一个地方抽象了你的逻辑,最合适的代码工具是一个开关盒-我的字典的例子,并没有给你任何好处,你可能会争辩说这会让事情变得不那么清楚。还有其他的选择,可能会把它抽象得更清楚一些,例如,在工厂启动或构建时加载的字典,带有一个字符串键和某种工厂委托,或者只是一个类型等。然而,我认为switch语句并非天生就坏——我认为这里的示例是一个很好的例子。您已经在一个地方抽象了逻辑,最合适的代码工具是switch case(我的字典示例),它并没有真正给您带来任何好处,您可能会认为它让事情变得不那么清楚。