Конструкторы с одинаковым типом аргумента

StackOverflow https://stackoverflow.com/questions/31215

  •  09-06-2019
  •  | 
  •  

Вопрос

У меня есть объект Person с двумя конструкторами - один принимает значение int (PersonID), другой - строку (logonName).Мне бы нужен другой конструктор, который принимает строку (badgeNumber).Я знаю, что это невозможно сделать, но, похоже, это обычная ситуация.Есть ли изящный способ справиться с этим?Я полагаю, это было бы применимо к любому перегруженному методу.Код:

public class Person
{
    public Person() {}

    public Person(int personId)
    {
        this.Load(personId);
    }

    public Person(string logonName)
    {
        this.Load(logonName);
    }

    public Person(string badgeNumber)
    {
        //load logic here...
    }

...и т.д.

Это было полезно?

Решение

Вы могли бы рассмотреть возможность использования пользовательских типов.

Например, создайте классы LogonName и BadgeNumber.

Тогда объявления ваших функций будут выглядеть следующим образом...

public Person(LogonName ln)
{
    this.Load(ln.ToString());
}

public Person(BadgeNumber bn)
{
    //load logic here...
}

Такое решение может дать вам хорошее место для сохранения бизнес-логики, которая управляет форматом и использованием этих строк.

Другие советы

Возможно, вы могли бы вместо этого использовать заводские методы?

public static Person fromId(int id) {
    Person p = new Person();
    p.Load(id);
    return p;
}
public static Person fromLogonName(string logonName) {
    Person p = new Person();
    p.Load(logonName);
    return p;
}
public static Person fromBadgeNumber(string badgeNumber) {
    Person p = new Person();
    // load logic
    return p;
}
private Person() {}

У вас есть четыре варианта, которые я могу придумать, три из которых уже были названы другими:

  1. Пройдите заводским маршрутом, как предлагают здесь несколько других.Одним из недостатков этого является то, что вы не можете получить согласованное именование из-за перегрузки (иначе у вас была бы та же проблема), поэтому оно внешне менее чистое.Другим, более крупным недостатком является то, что это исключает возможность выделения непосредственно в стеке.Все будет размещено в куче, если вы воспользуетесь таким подходом.

  2. Пользовательские оболочки объектов.Это хороший подход, и я бы порекомендовал его, если вы начинаете с нуля.Если у вас много кода, использующего, например, значки в виде строк, то переписывание кода может сделать этот вариант нежизнеспособным.

  3. Добавьте перечисление к методу, указав, как обращаться со строкой.Это работает, но требует, чтобы вы переписали все существующие вызовы, чтобы включить новое перечисление (хотя при желании вы можете указать значение по умолчанию, чтобы избежать некоторых из них).

  4. Добавьте фиктивный параметр, который не используется, чтобы различать две перегрузки.например ,Прикрепите а bool перейдем к методу.Этот подход используется стандартной библиотекой в нескольких местах, например std::nothrow является фиктивным параметром для operator new.Недостатки такого подхода заключаются в том, что он уродлив и не масштабируется.

Если у вас уже есть большая база существующего кода, я бы рекомендовал либо добавить перечисление (возможно, со значением по умолчанию), либо добавить фиктивный параметр.Ни то, ни другое не красиво, но и то, и другое довольно просто модернизировать.

Если вы начинаете с нуля или у вас есть только небольшой объем кода, я бы порекомендовал пользовательские оболочки объектов.

Заводские методы были бы вариантом, если у вас есть код, который сильно использует raw badge/logonName строк, но не сильно использует Person класс.

Если вы используете C # 3.0, вы можете использовать Инициализаторы объектов:

public Person()
{
}

public string Logon { get; set; }
public string Badge { get; set; }

Вы бы вызвали конструктор следующим образом:

var p1 = new Person { Logon = "Steve" };
var p2 = new Person { Badge = "123" };

Нет.

Вы могли бы рассмотреть поле флага (enum для удобства чтения), а затем попросить конструктор использовать htat, чтобы определить, что вы имели в виду.

Это не сработает.Вы могли бы рассмотреть возможность создания класса с именем BadgeNumber, который обертывает строку, чтобы избежать этой двусмысленности.

У вас не может быть двух разных конструкторов / методов с одинаковой сигнатурой, иначе, как компилятор может определить, какой метод запускать?

Как Сказал Зак, Я бы рассмотрел возможность создания класса "options", куда вы могли бы фактически передавать параметры, содержащиеся в пользовательском типе.Это означает, что вы можете в значительной степени передавать столько параметров, сколько захотите, и делать с опциями все, что вам нравится, только будьте осторожны, вы не создаете монолитный метод, который пытается сделать все..

Либо так, либо голосуйте за заводской узор..

Вы могли бы использовать статический заводской метод:

public static Person fromLogon(String logon) { return new Person(logon, null); }
public static Person fromBadge(String badge) { return new Person(null, badge); }

Как уже было предложено, в данном случае лучше использовать пользовательские типы.

Единственное, что я могу придумать, чтобы справиться с тем, что вы хотите сделать, - это иметь параметры, один из которых описывает тип параметра (перечисление с LogonName , BadgeNumer и т.д.), А второй - значение параметра.

Вы могли бы переключиться на шаблон в заводском стиле.

public class Person {

  private Person() {}

  public static PersonFromID(int personId)
  {
    Person p = new Person().
    person.Load(personID);

    return p;
    this.Load(personId);
  }

  public static PersonFromID(string name)
  {
    Person p = new Person().
    person.LoadFromName(name);

    return p;
  }

  ...
}

Или, как было предложено, используйте пользовательские типы.Вы также можете взломать что-то, используя дженерики, но я бы не рекомендовал это для удобства чтения.

Как насчет ...

public Person(int personId)
{
    this.Load(personId);
}

public Person(string logonName)
{
    this.Load(logonName);
}

public Person(Object badgeNumber)
{
    //load logic here...
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top