开发者

C# automatic properties - is it possible to have custom getter with default setter?

It's possible I shouldn't even be attempting this in the first place, but here's what I have so far:

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
}

How would I leave the above setter without any sort of custom logic? In the olden days I think you would just use:

set { authorIDs = value; }

which doesn't work now.

Is this whole idea just terrible to begin with?

Edit:

To answer so开发者_如何学运维me people's questions: I'm attempting to combine MVC with Data Annotation validation, with default binding, with Entity Framework 4.0...and failing quite fantastically, I believe.


No, it's not possible. Either everything is explicit, or the whole property is automatic. Anyway, in that case the setter doesn't seem to make any sense... there should be no setter at all.

Also, I think you should make it a method. It would make it clearer to the caller that it performs a possibly lenghty calculation. It's also against guidelines to perform complex processing in a property.


This answer goes a bit wider than simply getting rid of the setter on the property - combine it with the rest of the answers and comments, and take the bits that make sense. Hopefully the bit at the end will help too, maybe just not right now.

If you're using this in a model for data binding purposes and thus want it exposed as a property, I would do something like this:

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

Make a service which you will call to populate your model:

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

In your controller:

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

    return View(model);
}

I explicitly haven't included how to instantiate the book service in the controller. My preference would be to inject it at runtime in a constructor, but this will require you to have a custom controller factory - one step at a time. You could just new it up in the default constructor:

private readonly BookService service; 

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

In an ideal world though, I would do this:

private readonly BookService service; 

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

    this.service = service;
}

However the default MVC controller factory expects controllers to have a default parameter, so doing it with constructor injection will take a bit more work.


The default setter would create a backing variable at compile time with a name as follows:

[CompilerGenerated]
private string <AuthorIDs>k__BackingField;

Since this is created at compile time, it cannot be referenced in your code until it has been created, and in addition, the angle brackets (intentionally) are not permissable in variable names.

For this reason, it would be next to useless to allow something to be stored in this variable (which is essentially what that automatic setter does) with no way of accessing this value at any point in the future (after all the getter here is not an automatic getter it would return something entirely different)

So to summerise, without a getter, there would (which is the only way to retrieve the value from this backing variable) there would be no point in having a private setter


if you want to do it your way, just do the following:

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

but just like others are saying, this is an overkill for a property, put it in the method, something like

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


There is actually a way of doing that:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜