在C#中设置ICollection属性的值

5

我的类继承了一个接口,因此我需要在Person类中拥有emailaddress属性。

我的问题是如何最好地获取和设置该属性。

public class Contact : IPerson, ILocation
{
  ...
  [MaxLength(256)]
  public string EmailAddress { 
  get{
    return this.Emails.First().ToString();
  } 
  set{ ????  }
  }
  ....

  public virtual ICollection<Emails> Emails { get; set; }
}

本质上,我想让这个类允许多个电子邮件地址。

完全公开地说,我对此还比较陌生,可能没有提出正确的问题,但我已经搜索了一天半,没有看到类似的内容(不是我认为这很不寻常),希望能得到您的见解。

电子邮件类属性:

[Key]
public int Id { get; set; }

[MaxLength(256)]
    public string EmailAddress { get; set; }

如果你想要访问集合中的不同索引,仅仅使用getter和setter是不够的。你必须编写一个带有某种类型索引参数的方法。 - cppanda
1
从根本上说,拥有一个集合,但也拥有一个尝试处理单个值的属性是不寻常的。您希望它如何表现?如果我多次设置“EmailAddress”属性,这是否会导致一个地址还是多个地址?您希望它如何与设置“Emails”属性交互?实际的实现可能很简单-但是您首先需要确定所需的行为。 - Jon Skeet
我在联系人和他们的电子邮件之间建立了一对多关系(因此使用集合)。由于我继承了一个接口,所以无法排除EmailAddress属性(来自接口)。所以我不确定接下来该怎么做。我可以忽略设置并通过关系来完成吗? - utd1878
如果set是由接口的实现强制执行的,那么你不能“忽略”它。最好的方法是在set体中抛出一个NotImplementedException异常。虽然如此,但它必须存在。 - Simon Whitehead
4个回答

1

您是否对强制您实现EmailAddressIPerson接口设计具有控制权?如果是这样,我建议重新考虑设计,以避免在同一对象上需要一个单数属性和一个电子邮件地址列表。

您还可以考虑将Emails属性的setter设置为protected,以防止外部代码更改您的对象数据。

如果您必须实现此接口,并且希望EmailAddress属性始终引用集合中的第一个电子邮件,则可以尝试使用此代码。

public class Contact : IPerson, ILocation
{
  public Contact()
  {
    // Initialize the emails list
    this.Emails = new List<Emails>();
  }

  [MaxLength(256)]
  public string EmailAddress
  { 
    get
    {
      // You'll need to decide what to return if the first email has not been set.
      // Replace string.Empty with the appropriate value.
      return this.Emails.Count == 0 ? string.Empty : this.Emails[0].ToString();
    } 
    set
    {
      if (this.Emails.Count == 0)
      {
        this.Emails.Add(new Emails());
      }
      this.Emails[0].EmailAddress = value;
    }
  }

  public virtual IList<Emails> Emails { get; set; }
}

哎呀,Length 的问题你发现了,好事。根据我的注释,Add() 需要更新以创建一个新的 Emails 对象。由于你没有在代码中包含它,所以我不确定它是什么样子,因此无法告诉你更具体的信息。 - Jeromy Irvine
这是一个非常基本的类,它具有一个EmailAddress属性。它的唯一目的就是为每个联系人保存电子邮件。已更新原始内容以显示电子邮件类。 - utd1878
.Add(new Emails()) 只是将一个新的 Emails 对象放入列表中。this.Emails[0].EmailAddress = value 这一行实际上将传递给 setter 的值设置为任何内容。我将其放在 if 块之外,以避免重复分配 Emails.EmailAddress 属性。 - Jeromy Irvine
那么如果没有初始电子邮件,它会放置新的电子邮件对象,但是什么时候放置值呢?我可以看到如果已经有电子邮件存在,它会将其放入其中,但是在初始插入时发生了什么我并没有看到。再次说明,我对此还比较陌生,所以很抱歉问这些可能是基础问题的问题。 - utd1878
@JeromyIrvine 所以还有一个问题,现在它正在设置联系人类的EmailAddress和Emails类正在获取相同的值,从本质上讲给联系人提供了两个相同的电子邮件地址。我该如何控制这个? - utd1878
显示剩余6条评论

0

编辑:一开始我没有理解问题。

在这种情况下,我不确定您试图做什么是有意义的。您正在从getter中取出一组电子邮件中的第一个电子邮件;那么对于setter,您希望实现什么样的行为?它可以(a)将设置的值更新或插入到集合中的第一个位置,或者(b)只是在设置时将电子邮件添加到集合中。我不确定是否应该允许设置它,只需进行获取并将其留在那里即可。

我还会将属性重命名为FirstEmail或其他名称,以便明显地表明它来自可能的电子邮件集合。

  public string FirstEmailAddress { 
      get{
         return this.Emails.Count > 0 ? this.Emails.First().ToString() : string.Empty;
      } 
  }

0

根据您的评论,

我在联系人和他们的电子邮件之间有一个一对多的关系(因此使用集合)。由于我继承了一个接口,所以无法排除EmailAddress属性(来自接口)。所以我不确定该从哪里开始。我可以忽略设置并通过关系来完成吗?

您不应该允许 public setter。将其标记为虚拟后,将其设置为 protected

public virtual ICollection<Emails> Emails { get; protected set; }

对于您的EmailAddress设置器,您可以使用以下内容:

[MaxLength(256)]
public string EmailAddress 
{ 
    get
    {
        return this.Emails.DefaultIfEmpty(new EMail()).First().EmailAddress;
    } 
    set
    {
        if (Emails == null)
        {
            Emails = new Collection<Email>(); 
        }
        Emails.Items.Insert(0, new EMail {EmailAddress = value}); 
    }
}

不喜欢新的Collection<Email>声明。或者Items。 - utd1878
但是你暴露的是这样的。它应该被暴露为 IList<Email>。然后 Items 将会消失。你无法避免 Insert(除非它是双向链表或堆栈)。 - Tilak
抱歉,我的意思是编译器不会 :) - utd1878
我同意将Emails属性设置为受保护的,但我不喜欢这里EmailAddress的实现。如果在未初始化Emails的情况下调用getter,它会抛出错误,并且在setter中使用Insert将在每次调用setter时向列表中添加一个新项,我认为这并不是很理想的。 - Jeromy Irvine
@JeromyIrvine,否则第一个电子邮件地址将始终被覆盖。如果意图是覆盖,则可以使用Emails [0]。应在“ctor”中初始化“Emails”,并删除条件if(Emails == null)。 - Tilak
@Tilak,我理解你的代码是正确的,如果需要插入的话。但我认为最好不要使用setter来进行插入操作,这样会更加简洁。 - Jeromy Irvine

0
通常,当您想要向世界“展示”内部集合时,您所做的就是将其作为属性并仅创建一个getter。这样,您就不能像 Contact.Emails = new ICollection<Email>() 这样设置整个集合,这是一种不好的做法。但是,您可以通过 Contacts.Emails 访问集合并进行迭代或添加项目等操作。
如果您喜欢,还可以为此属性添加索引器:http://msdn.microsoft.com/en-us/library/vstudio/6x16t2tx(v=vs.100).aspx

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