问题描述
我正在尝试编写一个将给我HashSet集合的方法,然后我可以使用Contains()方法根据Contains()的时间复杂度来检查某些事物,因为HashSet为O(1)。这是一个简单的示例: 我写了两种方法,唯一的区别是返回类型。 GetNamesHashSet()返回特定的HashSet,GetNames()返回IEnumerable以使其通用。由于存在动态绑定,由于我在两个方法中都初始化了HaseSet变量,因此两者都将在运行时返回HashSet。在编译时,我们可以看到GetNames()应该返回IEnumerable。不过,我们可以声明一个变量aSet并调用HashSet从其他接口继承的其他方法。因此,两者都会给我们我们所需要的。由于用户无法使用该方法,因此他们从界面中知道的只是输出和输入。
我的问题是:
-
目的是通过调用GetNames()方法来使用HashSet的Contains()方法。一旦GetNames()方法将HashSet返回给调用方,我们就可以调用Contains()方法。那么哪种方式更适合这种情况?当我们编写GetNames()方法时返回IEnumerable或HashSet吗?
-
如果我返回IEnumerable(请参见下面的GetNames()方法的代码示例),为什么我们可以通过在主方法中声明变量aSet来调用aSet.Contains(),因为它是动态绑定,所以一旦我们声明为var aset = person.GetNames(),集合的类型为IEnumerable,IEnumerable仅具有方法GetEnumerator(),为什么集合具有方法Contains()?
public class Program
{
static void Main(string[] args)
{
var person = new Person() { Name = "a",Age = 20 };
HashSet<string> namesSet = person.GetNamesHashSet();
if (namesSet.Contains(person.Name))
{
Console.WriteLine(person.Age);
}
var aset = person.GetNames();
if (aset.Contains(person.Name))
{
Console.WriteLine(person.Age);
}
Console.ReadLine();
}
}
public interface IPerson
{
IEnumerable<string> GetNames();
HashSet<string> GetNamesHashSet();
}
public class Person :IPerson
{
public string Name { get; set; }
public int Age { get; set; }
public IEnumerable<string> GetNames()
{
HashSet<string> set = new HashSet<string>();
for (char c = 'a'; c < 'g'; c++)
{
set.Add(c.ToString());
}
return set;
}
public HashSet<string> GetNamesHashSet()
{
HashSet<string> hashSet = new HashSet<string>();
for (char c = 'a'; c < 'g'; c++)
{
hashSet.Add(c.ToString());
}
return hashSet;
}
}
解决方法
如果要将其暴露给外界,则理想的返回类型是ImmutableHashSet
。它在.Net Core中可用,并且可以在带有NuGet包的.Net Framework中使用。如果您不能或不想添加新的依赖项(这是合理的),则返回NET::ERR_CERT_COMMON_NAME_INVALID.
是下一个最佳选择。
在任何情况下效果都是相同的:您将返回最具体的类型,该类型不允许用户修改集合。这很重要,因为理想情况下,您希望缓存创建的集合,并在每次调用该方法时返回相同的对象,而不是每次都像当前那样重新生成它。 IReadOnlyCollection
快是因为HashSet.Contains
慢!
通过返回可写集合,您还暗示修改集合会以某种方式影响HashSet.Add
对象,但事实并非如此。如果您返回只读内容,则您的API更清晰,更简单。
关于在Person
与HashSet
(或实际上IEnumerable
)上调用“包含”,这是同一回事。在开始自己的测试之前,IReadOnlyCollection
方法将检查源对象是否实现Enumerable.Contains
并仅转发呼叫。