Frage

Ich habe ein Person-Objekt mit zwei Konstruktoren – einer nimmt einen int (personId), der andere einen String (logonName).Ich hätte gerne einen anderen Konstruktor, der eine Zeichenfolge (badgeNumber) akzeptiert.Ich weiß, dass dies nicht möglich ist, aber es scheint eine häufige Situation zu sein.Gibt es eine elegante Möglichkeit, damit umzugehen?Ich nehme an, dass dies für jede überladene Methode gelten würde.Code:

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

...usw.

War es hilfreich?

Lösung

Sie könnten die Verwendung benutzerdefinierter Typen in Betracht ziehen.

Erstellen Sie beispielsweise die Klassen „LogonName“ und „BadgeNumber“.

Dann sehen Ihre Funktionsdeklarationen so aus...

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

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

Eine solche Lösung könnte Ihnen einen guten Ort bieten, an dem Sie die Geschäftslogik aufbewahren können, die das Format und die Verwendung dieser Zeichenfolgen regelt.

Andere Tipps

Könnten Sie stattdessen vielleicht Factory-Methoden verwenden?

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

Mir fallen da vier Möglichkeiten ein, drei davon wurden bereits von anderen benannt:

  1. Gehen Sie den Werksweg, wie von mehreren anderen hier vorgeschlagen.Ein Nachteil dabei ist, dass Sie durch Überladung keine konsistente Benennung erzielen können (sonst hätten Sie das gleiche Problem), sodass es oberflächlich betrachtet weniger sauber ist.Ein weiterer, größerer Nachteil besteht darin, dass die Möglichkeit einer direkten Zuordnung auf dem Stapel ausgeschlossen ist.Bei diesem Ansatz wird alles auf dem Heap zugewiesen.

  2. Benutzerdefinierte Objekt-Wrapper.Dies ist ein guter Ansatz, den ich empfehlen würde, wenn Sie bei Null anfangen.Wenn Sie viel Code haben, der beispielsweise Abzeichen als Zeichenfolgen verwendet, kann das Umschreiben des Codes dazu führen, dass diese Option nicht mehr sinnvoll ist.

  3. Fügen Sie der Methode eine Enumeration hinzu, die angibt, wie die Zeichenfolge behandelt werden soll.Dies funktioniert, erfordert jedoch, dass Sie alle vorhandenen Aufrufe neu schreiben, um die neue Aufzählung einzuschließen (obwohl Sie bei Bedarf einen Standardwert angeben können, um einiges davon zu vermeiden).

  4. Fügen Sie einen nicht verwendeten Dummy-Parameter hinzu, um zwischen den beiden Überladungen zu unterscheiden.z.B.Tack a bool auf die Methode.Dieser Ansatz wird von der Standardbibliothek an einigen Stellen verfolgt, z. std::nothrow ist ein Dummy-Parameter für operator new.Die Nachteile dieses Ansatzes bestehen darin, dass er hässlich ist und nicht skalierbar ist.

Wenn Sie bereits über eine große Basis an vorhandenem Code verfügen, würde ich empfehlen, entweder die Enumeration (möglicherweise mit einem Standardwert) oder den Dummy-Parameter hinzuzufügen.Keines davon ist schön, aber beide lassen sich relativ einfach nachrüsten.

Wenn Sie bei Null anfangen oder nur wenig Code haben, würde ich die benutzerdefinierten Objekt-Wrapper empfehlen.

Die Factory-Methoden wären eine Option, wenn Sie Code haben, der das Raw stark nutzt badge/logonName Saiten, nutzt die aber nicht stark Person Klasse.

Wenn Sie C# 3.0 verwenden, können Sie verwenden Objektinitialisierer:

public Person()
{
}

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

Sie würden den Konstruktor folgendermaßen aufrufen:

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

NEIN.

Sie könnten ein Flag-Feld (Enum zur besseren Lesbarkeit) in Betracht ziehen und den Konstruktor dann mit htat ermitteln lassen, was Sie gemeint haben.

Das wird nicht funktionieren.Sie könnten erwägen, eine Klasse namens BadgeNumber zu erstellen, die eine Zeichenfolge umschließt, um diese Mehrdeutigkeit zu vermeiden.

Sie können nicht zwei verschiedene Konstruktoren/Methoden mit derselben Signatur haben. Wie kann der Compiler sonst bestimmen, welche Methode ausgeführt werden soll?

Als Sagte Zack, würde ich darüber nachdenken, eine „Options“-Klasse zu erstellen, in der Sie tatsächlich die in einem benutzerdefinierten Typ enthaltenen Parameter übergeben könnten.Das bedeutet, dass Sie so viele Parameter übergeben können, wie Sie möchten, und mit den Optionen machen können, was Sie wollen. Achten Sie nur darauf, dass Sie keine monolithische Methode erstellen, die versucht, alles zu tun.

Entweder das, oder dafür stimmen Fabrikmuster..

Sie könnten eine statische Factory-Methode verwenden:

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

Wie bereits vorgeschlagen, sind in diesem Fall benutzerdefinierte Typen die richtige Wahl.

Das Einzige, was mir einfällt, um mit dem umzugehen, was Sie tun möchten, ist, Parameter zu haben, einen, der den Parametertyp beschreibt (eine Aufzählung mit LogonName, BadgeNumer usw.), und der zweite ist der Parameterwert.

Sie könnten zu einem Muster im Fabrikstil wechseln.

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

  ...
}

Oder verwenden Sie, wie vorgeschlagen, benutzerdefinierte Typen.Sie können etwas auch mit Generika hacken, aber ich würde es aus Gründen der Lesbarkeit nicht empfehlen.

Wie wäre es mit ...

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

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

public Person(Object badgeNumber)
{
    //load logic here...
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top