Pregunta

Tengo un objeto Persona con dos constructores: uno toma un int (personId) y el otro una cadena (logonName).Me gustaría otro constructor que tome una cadena (badgeNumber).Sé que esto no se puede hacer, pero parece que podría ser una situación común.¿Existe una manera elegante de manejar esto?Supongo que esto se aplicaría a cualquier método sobrecargado.Código:

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

...etc.

¿Fue útil?

Solución

Podría considerar utilizar tipos personalizados.

Por ejemplo, cree clases LogonName y BadgeNumber.

Entonces tus declaraciones de funciones se ven así...

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

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

Esta solución podría ofrecerle un buen lugar para guardar la lógica empresarial que rige el formato y el uso de estas cadenas.

Otros consejos

¿Quizás podrías utilizar métodos de fábrica en su lugar?

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

Se me ocurren cuatro opciones, tres de las cuales ya han sido nombradas por otros:

  1. Siga la ruta de la fábrica, como lo sugieren varios otros aquí.Una desventaja de esto es que no puedes tener nombres consistentes a través de la sobrecarga (o de lo contrario tendrías el mismo problema), por lo que es superficialmente menos limpio.Otra desventaja mayor es que excluye la posibilidad de realizar asignaciones directamente en la pila.Todo se asignará en el montón si adopta este enfoque.

  2. Envoltorios de objetos personalizados.Este es un buen enfoque y el que recomendaría si comienza desde cero.Si tiene mucho código que utiliza, por ejemplo, insignias como cadenas, reescribir el código puede hacer que esta sea una opción no viable.

  3. Agregue una enumeración al método, especificando cómo tratar la cadena.Esto funciona, pero requiere que vuelvas a escribir todas las llamadas existentes para incluir la nueva enumeración (aunque puedes proporcionar una predeterminada si lo deseas para evitar algo de esto).

  4. Agregue un parámetro ficticio que no se utilice para distinguir entre las dos sobrecargas.p.ej.Virar un bool sobre el método.La biblioteca estándar adopta este enfoque en algunos lugares, p. std::nothrow es un parámetro ficticio para operator new.Las desventajas de este enfoque son que es feo y que no escala.

Si ya tiene una base grande de código existente, le recomendaría agregar la enumeración (posiblemente con un valor predeterminado) o agregar el parámetro ficticio.Ninguno de los dos es bonito, pero ambos son bastante sencillos de adaptar.

Si está comenzando desde cero o solo tiene una pequeña cantidad de código, le recomendaría los envoltorios de objetos personalizados.

Los métodos de fábrica serían una opción si tiene un código que utiliza mucho el formato sin formato. badge/logonName cuerdas, pero no usa mucho el Person clase.

Si está utilizando C# 3.0, puede utilizar Inicializadores de objetos:

public Person()
{
}

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

Llamarías al constructor así:

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

No.

Podrías considerar un campo de bandera (enumeración para facilitar la lectura) y luego hacer que el constructor use htat para determinar lo que quieres decir.

Eso no funcionará.Podría considerar crear una clase llamada BadgeNumber que envuelva una cadena para evitar esta ambigüedad.

No puede tener dos constructores/métodos diferentes con la misma firma; de lo contrario, ¿cómo puede el compilador determinar qué método ejecutar?

Como zack dijo, Consideraría crear una clase de "opciones" donde realmente se pudieran pasar los parámetros contenidos en un tipo personalizado.Esto significa que puedes pasar tantos parámetros como quieras y hacer lo que quieras con las opciones, solo ten cuidado de no crear un método monolítico que intente hacerlo todo.

O eso, o votar por el patrón de fábrica..

Podrías usar un método de fábrica estático:

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

Como se ha sugerido, los tipos personalizados son el camino a seguir en este caso.

Lo único que se me ocurre para manejar lo que quieres hacer es tener parámetros, uno que describa el tipo de parámetro (una enumeración con LogonName, BadgeNumer, etc.) y el segundo es el valor del parámetro.

Podrías cambiar a un patrón de estilo de fábrica.

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

  ...
}

O, como se sugiere, utilice tipos personalizados.También puedes hackear algo usando genéricos, pero no lo recomendaría por razones de legibilidad.

Qué tal si ...

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

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

public Person(Object badgeNumber)
{
    //load logic here...
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top