Simplify Constructor for class with multiple initialisable fields

时间:2015-11-12 11:53:52

标签: c# constructor-overloading

I currently have the following problem:
I have a class which includes 3 different fields

  • Enum x
  • ActiveDirectoryUser y
  • CustomClass z

The enum can be initialised by passing a string or the enum object. The ADUser can be initialised by passing a string (LoginName) or the user by itself and the CustomClass can be initialized by passing a string, int or the object.

Now I want to initialize the class to pass all different combinations like

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

Is there a way to simplify the constructors without typing all of the 12 possibilities (Enum-2 * ADUser-2 * CClass-3 = 12)?

I thought about chained constructors where i also ended up with 12 constructors but also thought about just passing the c# Object on each parameter and cast it and do stuff with it but i think that is just a dirty workaround?

Edit

The class is contained in an library and so can be used internal but also public. For the internal uses there is no problem to pass a concrete version of an object. But if i use it public in other solutions these solutions can only refer to string or int values. So the class should be able to 'take' the values and convert them while beeing initialised because it have access to all the real objects.
Maybe this clarifies the problem a bit.

Here some code snippets with changed names:

#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

2 个答案:

答案 0 :(得分:1)

If your class has only 3 properties (EnumValue, ADUser, CustomClass) then you should have only one constructor with these :class(EnumValue enumValue, ADUser adUser, CustomClass customClass). The ADUser and CustomClass should be instantiated outside of your class using their constructor which support string or int, etc; Example:

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

Edit You can use it like I described above for internal scope and for the public part you can use and expose a factory (wrapper) class which actually can receive users and other parameters as strings or int and internally instantiate and return your class.

In addition to your snippet: Create a proxy like public class in your assembly that can be accessed from outside (from other assemblies).Make your class internal:

   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()
        }
}

The builder class can use whatever method you want to build the ClassName object; This way you can expose all your class methods without using multiple constructors.

答案 1 :(得分:0)

我认为最好的办法是使用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#扩展方法wizadry的扩展构建器模式):

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; }
}

通过这种方式,您可以以一种舒适的方式构造需要许多构造函数参数的实例。