我有一个与数据库通信的应用程序。每个表都有一个唯一的ID。
当我从数据库中拉出一行时,我会填充一个包含所有字段的类(这是所有生成的代码)。
我最初只使用Int32作为ID的类型,但一直发现不合适的类型被传递给方法等。
我的解决方案是创建一个我称之为idUser的特定类型(其中User是实际的表名)。这样做的原因是,如果我尝试将idSalesMan传递给期望idUser的方法,它会产生编译时错误,这非常有用并且阻止我制造学校错误。
idUser背后的代码是这样的..
[Serializable]
public struct idUser : IComparable
{
public idUser(int InitVal) { this.m_Main=InitVal; }
private int m_Main;
public int Main { get { return m_Main; } set { m_Main = value; }}
public static implicit operator int(idUser Main) { return Main.m_Main; }
public static implicit operator idUser(int Main) { return new idUser(Main); }
public static bool operator ==(idUser one, idUser two) { return one.m_Main == two.m_Main; }
public static bool operator !=(idUser one, idUser two) { return one.m_Main != two.m_Main; }
public static bool operator <(idUser one, idUser two) { return one.m_Main < two.m_Main; }
public static bool operator >(idUser one, idUser two) { return one.m_Main > two.m_Main; }
public override string ToString() {{ return this.m_Main.ToString(CultureInfo.InvariantCulture); }}
public override bool Equals(object obj) { return this.m_Main == ((idUser)obj).m_Main; }
public override int GetHashCode() { return this.m_Main.GetHashCode(); }
public int CompareTo(object obj) { return this.m_Main.CompareTo(((idUser)obj).m_Main); }
}
这很好用,很容易(因为它是由我编写的工具生成的),并且可以防止我上面提到的问题。
但是,由于我的数据库有大约100个表,因此它会生成大量代码和相当大的可执行文件。 (这不是主要问题)。
我很好奇使用上述结构而不仅仅是标准的Int32对性能的影响,我感到非常震惊。
创建一个List<>
填充它,然后检查是否存在某些键..
使用List<idUser>
时,填充它需要花费3倍的时间,检查一些添加的项目需要5倍的时间。
这是一个非常重要的打击,因此我正在寻找其他方法。
理想情况下,我希望能够说...
public struct idUser : Int32 { }
public struct idCustomer : Int32 { }
但这显然不起作用。
正如我上面所说,它可以正常工作,但只是性能受到打击。有没有人对如何结合严格的类型检查有任何想法,同时保留Int32的性能?
感谢。
答案 0 :(得分:3)
我怀疑我可以通过在List<T>
中找到值来解释性能问题 - 您没有实现IEquatable<T>
,因此任何Equals
调用都必须将其与之比较的值设置为空。您还应该实施IComparable<T>
进行比较。
// Please don't use camelCased type names...
// I'd probably use UserId, CustomerId etc, partly to avoid non-interfaces
// starting with I.
public struct IdUser : IComparable, IComparable<IdUser>, IEquatable<IdUser>
{
...
public bool Equals(IdUser other) { return m_Main == other.m_Main; }
public int CompareTo(IdUser other) { return m_Main.CompareTo(other.mMain); }
}
您可能会发现只有这种变化才能将性能提升到可接受的水平。当填充列表时,它无济于事 - 但这取决于您所需的操作。
请注意,在大多数情况下,我希望大部分性能命中都是从数据库传输数据开始;比较仅使用内存数据填充列表的性能并不是对真实应用程序性能影响的真实测试。
答案 1 :(得分:1)
性能问题似乎在执行以下操作:
创建列表&lt;&gt;填充它,然后检查是否存在 一些关键..
这几乎可以肯定是因为你的类型没有实现IEquatable<T>
,导致在进行相等比较时进行装箱。实现此接口并检查是否可以改善这一点。
List<T>
依靠EqualityComparer<T>.Default
执行相等比较(例如,当您调用Contains
时)。现在,如果可能,此比较器会尝试使用Equals(T other)
中的IEquatable<T>
方法,这样可以避免装箱值类型。如果类型没有实现接口,则它会回退到object.Equals(object obj
),这需要将值类型装箱。
当然,处理所有性能问题的唯一方法是基准测试和配置文件。
另外请注意,您确定不想使用集合,例如HashSet<T>
而不是列表吗?在循环中调用List<T>.Contains
强烈暗示您需要set-semantics而不是list-semantics。
答案 2 :(得分:1)
区分基本上是Int32的多种类型
使用枚举怎么样?