【问题标题】:Simplify Constructor for class with multiple initialisable fields简化具有多个可初始化字段的类的构造函数
【发布时间】:2015-11-12 11:53:51
【问题描述】:

我目前遇到以下问题:
我有一个包含 3 个不同字段的类

  • 枚举 x
  • ActiveDirectory 用户
  • 自定义类 z

可以通过传递字符串或枚举对象来初始化枚举。 ADUser 可以通过传递字符串 (LoginName) 或用户本身来初始化,而 CustomClass 可以通过传递字符串、int 或对象来初始化。

现在我想初始化类以传递所有不同的组合,例如

class(string enumValue, string adUser, string customClass) 
class(string enumValue, ADUser adUser, CustomClass customClass)
class(EnumValue enumValue, string adUser, CustomClass customClass)

有没有一种方法可以在不输入所有 12 种可能性的情况下简化构造函数 (Enum-2 * ADUser-2 * CClass-3 = 12)?

我想到了链式构造器,我最终也得到了 12 个构造器,但也考虑过只在每个参数上传递 c# 对象并对其进行强制转换并对其进行处理,但我认为这只是一个肮脏的解决方法?

编辑

该类包含在库中,因此可以在内部使用,也可以在公共使用。对于内部使用,传递对象的具体版本没有问题。 但是,如果我在其他解决方案中公开使用它,这些解决方案只能引用字符串或 int 值。因此,该类应该能够在初始化时“获取”这些值并转换它们,因为它可以访问所有真实对象。
也许这可以稍微澄清一下问题。

这里有一些改名的代码sn-ps:

#region Content of libraryOne

public class ClassName
{
    internal EnumValueWrapper { get; set; }
    internal CustomClass { get; set; }
    internal ADUser { get; set; }

    public ClassName() { ... } //Now via Builder Pattern
    internal ClassName() { ... } //With Parameters for internal initialisations

    public InformationContainer GetContentInfo()
    {
        //[...]Process Stuff and Return Container
    }
}

internal CustomClass { ... }
internal EnumValueWrapper { ... }
internal ADUser { ... }

#endregion Content of libraryOne

【问题讨论】:

  • 我建议不要允许除了初始化构造函数的对象的具体版本之外的任何内容。所以 class(EnumValue enumvalue, ADUser adUser, CustomClass customClass) 将是我唯一的构造函数。但是没有看到更多代码以及它是如何架构的,我不知道这是否可行。
  • JamesThorpe ADUser、EnumValue 和 CustomClass 都已预先初始化。该类应该从它可以访问的池中选择正确的一个。 DanielCasserly 我会更新一些架构信息
  • 考虑在codereview.stackexchange.com 上提出这个问题,或者在那个网站上寻找类似的问题
  • 您在错误的层面上解决了这个问题。尽可能添加隐式或显式转换,或者只是让调用者传递正确的类型。那么你只需要一个构造函数:EnumValue, ADUser, CustomClass.

标签: c# constructor-overloading


【解决方案1】:

如果您的类只有 3 个属性 (EnumValue, ADUser, CustomClass),那么您应该只有一个具有这些属性的构造函数:class(EnumValue enumValue, ADUser adUser, CustomClass customClass)ADUserCustomClass 应该使用它们支持 stringint 等的构造函数在你的类之外实例化; 示例:

class (EnumValue param, new ADUser(string_param), new CustomClass(int_param));
class (EnumValue param, new ADUser(ADUser_param), new CustomClass(string_param));

编辑 您可以像我上面描述的那样将它用于内部范围,对于公共部分,您可以使用并公开一个工厂(包装器)类,该类实际上可以接收用户和其他参数作为字符串或 int 并在内部实例化并返回您的类。

除了你的 sn-p: 在你的程序集中创建一个类似 public 类的代理,可以从外部(从其他程序集)访问。使你的类内部:

   public class ClassNameBuilder
   {
        private ClassName _className;

        public ClassNameBuilder(string enumValue, string user, string custom_class) 
        { 
           _className = new ClassName(EnumToString, new User(user), new CustomClass(custom_class));

        } 

        public void CallClassNameMethod1()
        {
            return _className.Method1()
        }

        public void CallClassNameMethod2()
        {
            return _className.Method2()
        }
}

builder 类可以使用任何你想构建 ClassName 对象的方法;这样您就可以在不使用多个构造函数的情况下公开所有类方法。

【讨论】:

  • 是的,这可以解决问题,但我忘了提到图书馆的限制。我编辑了我的帖子。谢谢。
【解决方案2】:

我认为最好的办法是使用 Builder 模式。您甚至可以将它与派生类一起使用。

我要建立的课程:

public class MyBaseClass
{
    public MyBaseClass(SomeEnum enumValue, User user)
    {
    }
}

public class MyDerivedClass : MyBaseClass
{
    public MyDerivedClass(SomeEnum enumValue, User user, CustomClass customStuff)
        : base(enumValue, user)
    {
    }
}

现在让我们添加一个构建器类,其中包含一个额外的扩展类,以使事情变得更加舒适(它是一种使用 C# 扩展方法向导的扩展构建器模式):

public class MyBaseClassBuilder
{
    public SomeEnum EnumValue { get; set; }

    public User User { get; set; }
}

public static class MyBaseClassBuilderExtensions
{
    public static T SetEnumValue<T>(this T instance, SomeEnum value)
        where T : MyBaseClassBuilder
    {
        instance.EnumValue = value;
        return instance;
    }

    public static T SetEnumValue<T>(this T instance, string value)
        where T : MyBaseClassBuilder
    {
        instance.EnumValue = (SomeEnum)Enum.Parse(typeof(SomeEnum), value);
        return instance;
    }

    public static T SetUser<T>(this T instance, User value)
        where T : MyBaseClassBuilder
    {
        instance.User = value;
        return instance;
    }

    public static T SetUser<T>(this T instance, string value)
        where T : MyBaseClassBuilder
    {
        instance.User = new User(value);
        return instance;
    }

    public static MyBaseClass Build(this MyBaseClassBuilder instance)
    {
        return new MyBaseClass(instance.EnumValue, instance.User);
    }
}

现在让我们对派生类做同样的事情:

public class MyDerivedClassBuilder : MyBaseClassBuilder
{
    public CustomClass CustomStuff { get; set; }
}

public static class MyDerivedClassBuilderExtensions
{
    public static T SetCustomStuff<T>(this T instance, CustomClass value)
        where T : MyDerivedClassBuilder
    {
        instance.CustomStuff = value;
        return instance;
    }

    public static T SetCustomStuff<T>(this T instance, string value)
        where T : MyDerivedClassBuilder
    {
        instance.CustomStuff = new CustomClass(value);
        return instance;
    }

    public static MyDerivedClass Build(this MyDerivedClassBuilder instance)
    {
        return new MyDerivedClass(instance.EnumValue, instance.User, instance.CustomStuff);
    }
}

现在你可以用一些流畅的 API 风格构建你的实例了:

    static void Main(string[] args)
    {
        MyBaseClass baseInstance = new MyBaseClassBuilder()
            .SetEnumValue("Alpha")
            .SetUser("Big Duke")
            .Build();

        MyDerivedClass derivedInstance = new MyDerivedClassBuilder()
            .SetEnumValue(SomeEnum.Bravo)
            .SetUser(new User("Lt. Col. Kilgore"))
            .SetCustomStuff("Smells like victory")
            .Build();
    }

最后是其他类型:

public enum SomeEnum
{
    Alpha,
    Bravo
}

public class User
{
    public User(string name)
    {
        this.Name = name;
    }

    public string Name { get; private set; }
}

public class CustomClass
{
    public CustomClass(string notation)
    {
        this.Notation = notation;
    }

    public string Notation { get; private set; }
}

通过这种方式,您可以轻松地构造需要许多构造函数参数的实例。

【讨论】:

  • 哇,这太棒了。从未听说过“建造者模式”。 真丢脸 我想即使我不能直接使用类构造函数,这也能完成工作。如果有办法以这种方式使用该构造,我会感到自豪(只是为了代码清洁),但现在我会将您的答案标记为解决方案。谢谢!
  • 我不太明白您的代码中的 internal 是什么。你能给我一个代码摘录吗?或者告诉我代码示例的哪些部分必须更改或制作为内部
  • 嗯,我试试。在我的例子中,该类与 CustomClass、EnumValue 和 User 一起在一个库中。其他 3 个类有一个可能项目的内部列表,每个项目都通过静态构造函数填充,并且都有一个内部构造函数。所以只有类可以创建新的一个或每个类本身。类中的字段也是内部的,因此除了通过类的公共方法外,没有人可以从外部查看其内容。对于外部,我的意思是图书馆中不包含的课程。这有点解释了吗?
  • 说实话:不。你说 List of possible items which are 每个 填充 通过 a 静态 构造函数。您真的是指静态构造函数吗?还是您的意思是静态构造方法?但是:如果我看不到具体代码,我想我帮不了你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-11
  • 2016-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多