C#自动属性——是否可以具有默认设置器的自定义getter?

12

我可能根本不应该首先尝试这个,但以下是我目前的进展:

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
}

我该如何在不使用任何自定义逻辑的情况下离开上述setter?在旧时代,我想你只需使用:

set { authorIDs = value; }

现在无法运行。

这个想法本来就很糟糕吗?

编辑:

回答一些人的问题:我试图将MVC与数据注释验证、默认绑定和Entity Framework 4.0结合起来...但是我相信我失败了。


3
你有一个调用数据库的属性?疯了吧,把它放到一个方法中。 - RPM1984
我同意上面两条评论,而且写一个 setter 真的那么难吗?人们担心的事情让我感到惊讶... - Ed S.
2
此属性应该与对象的特定实例相关联(除非它是静态的,而这不是),它不需要“去其他地方”执行逻辑。另外你如何“设置”这个属性呢?它在数据库中,你会用值(列表)替换所有记录吗? - RPM1984
我同意上面的评论,但还需要补充一点,如果你必须有这样一个复杂的getter,我不明白为什么你需要setter。这里的意图是什么? - Darko
1
@Michael Shimmins - 像真正的澳大利亚人一样说话(只有澳大利亚人才知道)。=) - RPM1984
显示剩余7条评论
5个回答

10
不,这是不可能的。要么一切都是明确的,要么整个属性都是自动的。无论如何,在这种情况下,setter似乎没有任何意义...根本就不应该有setter。
另外,我认为你应该将其作为一个方法。这会让调用者更清楚地知道它执行了一个可能很长的计算。在属性中执行复杂处理也违反了准则。

请原谅我的无知,但在这种情况下推荐使用什么样的方法? - asfsadf
嗯,一个驻留在DAL中的? - RPM1984
"public List<int> GetAuthorIDs()" 实现你那里的确切代码 :-) - Carson63000
@PolishedTurd,请看Carson63000的评论。然而,你应该避免返回List<T>。最好返回一个IList<T>,这样你就可以返回另一个列表实现而不会破坏客户端代码。 - Thomas Levesque
@dtb - 或者更好的是,ICollection<T> - RPM1984
显示剩余5条评论

4
默认的 setter 方法将在编译时创建一个名为以下内容的后备变量:
[CompilerGenerated]
private string <AuthorIDs>k__BackingField;

由于这是在编译时创建的,因此在创建之前无法在代码中引用它。此外,尖括号(故意)不能用作变量名。
因此,允许将某些内容存储在此变量中(本质上就是自动设置器所做的事情)却没有任何方法在将来的任何时间访问此值几乎没有意义(毕竟,此处的getter不是自动getter,它将返回完全不同的内容)。
因此,总结一下,如果没有getter(从这个后备变量检索值的唯一方法),那么拥有私有setter就没有意义。

4
这个答案不仅仅是简单地去掉属性上的setter - 结合其他答案和评论,选择有意义的部分。希望最后一部分也能有所帮助,只是现在可能还不太明显。
如果你想将其用于数据绑定模型并希望将其作为属性公开,我建议这样做:
public class BookModel
{
    public IList<int> AuthorIds { get; set; }
}

创建一个服务,你可以调用它来填充你的模型:

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

在您的控制器中:
public ViewResult List(int id)
{
    var model = new BookModel 
    {
        AuthorIds = service.GetAuthorIDs(id)
    };

    return View(model);
}

我故意没有包括如何在控制器中实例化图书服务。我的偏好是在构造函数中运行时注入它,但这将要求您拥有自定义控制器工厂 - 一步一步来。您可以在默认构造函数中进行新的实例化:

private readonly BookService service; 

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

在理想情况下,我会这样做:
private readonly BookService service; 

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

    this.service = service;
}

然而默认的MVC控制器工厂期望控制器具有默认参数,因此使用构造函数注入会需要更多的工作。


2
注意:在GetAuthorIDs的foreach循环中,ToList()是多余的。 - Bear Monkey

2
如果您想按照自己的方式进行操作,只需要执行以下步骤:
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?
}
}

但就像其他人所说的那样,这对于一个属性来说有些过度了,应该将其放入方法中,例如:

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
设置一个从未使用的字段有什么意义呢?可以创建一个空的setter,或者更好的做法是:根本不设置setter... - Thomas Levesque
@Thomas:刚刚添加了一条评论,内容正是这个 :) - roman m
我试图利用MVC框架中的自动绑定功能,这是唯一的原因。 - asfsadf

0

实际上有一种方法可以做到这一点:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接