10) Now, we're getting a bit more hardcore... Again, please keep in mind that this is based on the profiler's results and Mr. Profiler says that in my simple test run there were over 310 million calls to the overloaded == operator of the Symbol class which results in 16 seconds of pure CPU time - So here are my 5 cents around that particular bit.
In the Symbol class, you have (more or less) the following methods:
public override bool Equals(object obj)
{
Symbol other = obj as Symbol;
if (other != (Symbol) null)
return this.Equals(other);
else
return false;
}
public bool Equals(Symbol other)
{
if (other == (Symbol) null)
return false;
if (object.ReferenceEquals((object) this, (object) other))
return true;
if (this.GetHashCode() != other.GetHashCode() || (!other.name.Equals(this.name) || !other.exchange.Equals(this.exchange) || (!other.currencyType.Equals((object) this.currencyType) || !other.assetType.Equals((object) this.assetType)) || (!other.contract.Equals((object) this.contract) || !other.expirationDate.Equals(this.expirationDate))))
return false;
else
return other.strikePrice.Equals(this.strikePrice);
}
public static bool operator ==(Symbol s1, Symbol s2)
{
if (object.ReferenceEquals((object) s1, (object) null))
return object.ReferenceEquals((object) s2, (object) null);
else
return s1.Equals(s2);
}
In both Equal methods, the first if-statement will result in an unneccessary and costly call to your overloaded
== operator implementation which - due to its very own implementation inevitably results in another call to Equals(Symbol) which in turn will call the overloaded equality operator one more time which eventually will return false for a non-null object that got thrown as a parameter at the Equals method it in the first place.
Let me rephrase that since I'm starting to get confused myself and also feel free to take a look at the attached screenshots as a reference.,,
Imagine you have a bog standard
Dictionary<Symbol, SymbolInfo> symbolInfoCache
like you do quite a bit in your code and access it like
symbolInfoCache[someSymbol]
. This will cause the ObjectEqualityComparer that gets used by default by the
Dictionary<Symbol, SymbolInfo>.FindEntry(TKey key)
method to call the
Symbol.Equals(object)
method passing a most likely non null reference to
someSymbol
And now, the whole chain starts ("a" being any of the symbols in the dictionary and "someSymbol" being a non null reference to the symbol that you pass to the dictionary's indexer):
symbolInfoCache[someSymbol] -> Dictionary.FindEntry(someSymbol) -> *now, there's even a loop over some parts of the dictionary* -> ObjectEqualityComparer.Equals(a, someSymbol)
-> a.Equals(
object someSymbol)
..-> !=(someSymbol, null)
....-> !(== operator(someSymbol, null))
......-> someSymbol.Equals(
Symbol null)
........-> ==(null, null)
......<- true
....<- false
..<- true
..-> a,Equals(
Symbol someSymbol)
....-> ==(someSymbol, null)
......-> someSymbol.Equals(
Symbol null)
........-> ==(null, null)
......<- true
....<- false
..<- now, a and someSymbol actually get compared and a proper result gets returned
<- proper result.
So to cut a long story short, I would suggest you replace those == and != checks with a version that's either based on "System.Object.ReferenceEquals(other, null)" or alternatively using a cast "(object)other == null".
Also, there are other parts in your code like FrequencyManager.FreqKey.Equals and FrequencyManager.FreqKey.GetHashCode where you're got the same issue in a slightly milder version. It might be worth to rewrite the == operator based on something like http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspxDear, dear, dear... Gotta go to bed now. More soon.