2010-09-23 14 views
7

Es posible que ni siquiera debería estar tratando esto en primer lugar, pero esto es lo que tengo hasta ahora:Propiedades automáticas de C#: ¿es posible tener un getter personalizado con setter predeterminado?

public List<int> AuthorIDs 
{ 
    get 
    { 
     var l = new List<int>(); 
     using (var context = new GarbageEntities()) 
     { 
      foreach (var author in context.Authors.Where(a => a.Books.Any(b => b.BookID == this.BookID)).ToList()) 
      { 
       l.Add(author.AuthorID); 
      } 
     } 
     return l; 
    } 
    set; //compiler error 
} 

¿cómo iba a salir de la incubadora anteriormente sin ningún tipo de lógica personalizada? En los viejos tiempos creo que simplemente usaría:

set { authorIDs = value; } 

que no funciona ahora.

¿Es esta idea tan terrible como para empezar?

Editar:

para contestar las preguntas de algunas personas: Estoy intentando combinar MVC con la validación de datos de anotación, con la unión por defecto, con Entity Framework 4.0 ... y fallando bastante fantástica, creo.

+3

por lo que tienen una propiedad que está llamando a una base de datos? loco, ponlo en un método. – RPM1984

+0

Su getter es demasiado complejo para una propiedad. – dtb

+0

Estoy de acuerdo con los dos comentarios anteriores, ¿y realmente es tan difícil simplemente escribir el colocador usted mismo? La gente de los tings se preocupa por sorprenderme ... –

Respuesta

4

Esta respuesta va un poco más allá de simplemente deshacerse del colocador en la propiedad - combinarlo con el resto de las respuestas y comentarios, y tomar los bits eso tiene sentido. Afortunadamente, el final también ayudará, quizás no ahora mismo.

Si está usando esto en un modelo para los propósitos de enlace de datos y por lo tanto lo quiere expuesto como una propiedad, me gustaría hacer algo como esto:

public class BookModel 
{ 
    public IList<int> AuthorIds { get; set; } 
} 

Hacer un servicio que va a llamar para poblar su modelo:

public class BookService() 
{ 
    public List<int> GetAuthorIDs(int bookId) 
    { 
     var authorIds = new List<int>(); 
     using (var context = new GarbageEntities()) 
     { 
      foreach (var author in context.Authors.Where(
       a => a.Books.Any(b => b.BookID == bookId))) 
      { 
       authorIds.Add(author.AuthorID); 
      } 
     } 
     return authorIds; 
    } 
} 

En su controlador:

public ViewResult List(int id) 
{ 
    var model = new BookModel 
    { 
     AuthorIds = service.GetAuthorIDs(id) 
    }; 

    return View(model); 
} 

que explícitamente refugio 't incluyó cómo crear una instancia del servicio de libros en el controlador. Mi preferencia sería inyectarlo en tiempo de ejecución en un constructor, pero esto requerirá que tenga una fábrica de controladores personalizada, paso a paso. Se podía nueva que en el constructor por defecto:

private readonly BookService service; 

public BookController() 
{ 
    service = new BookService(); 
} 

En un mundo ideal, sin embargo, me gustaría hacer esto:

private readonly BookService service; 

public BookController(BookService service) 
{ 
    if(service == null) 
     throw new ArgumentException("service must be supplied"); 

    this.service = service; 
} 

Sin embargo, el MVC fábrica controlador por defecto espera controladores tengan un parámetro por defecto, por lo que hacerlo con la inyección de constructor requerirá un poco más de trabajo.

+0

Gracias por tomarse el tiempo para mostrar todo este código. – asfsadf

+2

+1 para el ejemplo de código. Nota: ToList() es redundante en el bucle foreach GetAuthorIDs. –

+0

Gracias - actualizado. –

7

No, no es posible. O todo es explícito o toda la propiedad es automática. De todos modos, en ese caso, el colocador no parece tener sentido ... no debería haber ningún setter en absoluto.

Además, creo que deberías hacerlo un método. Sería más claro para la persona que llama que realiza un cálculo posiblemente largo. También es contrario a las pautas realizar un procesamiento complejo en una propiedad.

+0

Disculpe mi ignorancia, pero ¿qué tipo de método se recomienda en este caso? – asfsadf

+0

Um, ¿uno que reside en un DAL? – RPM1984

+0

"public List GetAuthorIDs()" implementando el código exacto que tiene allí :-) – Carson63000

2

si quiere hacerlo a su manera, simplemente hacer lo siguiente:

private List<int> authorIDs; 
public List<int> AuthorIDs 
{ 
    get 
    { 
     var l = new List<int>(); 
     using (var context = new GarbageEntities()) 
     { 
      foreach (var author in context.Authors.Where(a => a.Books.Any(b => b.BookID == this.BookID)).ToList()) 
      { 
       l.Add(author.AuthorID); 
      } 
     } 
     return l; 
    } 

    set{authorIDs = value; //this does not make much sense though ... what are you trying to do by setting authorIDs? 
} 
} 

pero al igual que otros dicen, esto es una exageración para una propiedad, lo puso en el método, algo así como

public List<int> GetAuthorIDs(int bookId) 
    { 
      var l = new List<int>(); 
      using (var context = new GarbageEntities()) 
      { 
       foreach (var author in context.Authors.Where(a => a.Books.Any(b => b.BookID == bookId)).ToList()) 
       { 
        l.Add(author.AuthorID); 
       } 
      } 
      return l; 
     } 
+1

¿De qué sirve establecer un campo que nunca usas? Crea un setter vacío, o mejor: sin setter en absoluto ... –

+0

@Thomas: acaba de agregar un comentario diciendo exactamente eso :) –

+0

Estaba tratando de aprovechar el enlace automático en el framework MVC. Esa es la única razón. – asfsadf

3

El colocador predeterminado crearía una variable respaldo en tiempo de compilación con un nombre de la siguiente manera:

[CompilerGenerated] 
private string <AuthorIDs>k__BackingField; 

Dado que se crea en tiempo de compilación, no se puede hacer referencia en el código hasta que se haya creado, y además, los corchetes angulares (intencionalmente) no son permisibles en nombres de variable.

Por esta razón, sería casi inútil permitir que algo se almacene en esta variable (que es esencialmente lo que hace el setter automático) sin posibilidad de acceder a este valor en cualquier momento en el futuro (después de todo getter aquí no es un getter automático devolvería algo completamente diferente)

Así que para summerise, sin getter, habría (que es la única manera de recuperar el valor de esta variable de respaldo) no tendría sentido tener un setter privado

+0

Gracias por esta explicación. – asfsadf

0

realidad, hay una forma de hacerlo:

public List<int> AuthorIDs 
{ 
    get 
    { 
     var l = new List<int>(); 
     using (var context = new GarbageEntities()) 
     { 
      foreach (var author in context.Authors.Where(a => a.Books.Any(b => b.BookID == this.BookID)).ToList()) 
      { 
       l.Add(author.AuthorID); 
      } 
     } 
     return l; 
    } 
    set{ 
     this.SetPropertyValue(page => page.AuthorIDs, value); 
    } 
} 
Cuestiones relacionadas