/// <summary>
        /// Compare one assembly name to another.
        /// </summary>
        /// <param name="that"></param>
        /// <returns></returns>
        internal int CompareTo(AssemblyNameExtension that)
        {
            // Are they identical?
            if (this.Equals(that))
            {
                return(0);
            }

            // Are the base names not identical?
            int result = CompareBaseNameTo(that);

            if (result != 0)
            {
                return(result);
            }

            // We need some collating order for these, alphabetical by FullName seems as good as any.
            return(String.Compare(this.FullName, that.FullName, StringComparison.OrdinalIgnoreCase));
        }
        /// <summary>
        /// Compare two base names as quickly as possible.
        /// </summary>
        /// <param name="that"></param>
        /// <returns></returns>
        internal int CompareBaseNameTo(AssemblyNameExtension that)
        {
            int result = CompareBaseNameToImpl(that);

#if DEBUG
            // Now, compare to the real value to make sure the result was accurate.
            AssemblyName a1 = this.asAssemblyName;
            AssemblyName a2 = that.asAssemblyName;
            if (a1 == null)
            {
                a1 = new AssemblyName(this.asString);
            }
            if (a2 == null)
            {
                a2 = new AssemblyName(that.asString);
            }

            int baselineResult = String.Compare(a1.Name, a2.Name, StringComparison.OrdinalIgnoreCase);
            Debug.Assert(result == baselineResult, "Optimized version of CompareBaseNameTo didn't return the same result as the baseline.");
#endif
            return(result);
        }
        /// <summary>
        /// Compare two assembly names for equality.
        /// </summary>
        /// <param name="that"></param>
        /// <returns></returns>
        internal bool Equals(AssemblyNameExtension that)
        {
            // Pointer compare.
            if (this == that)
            {
                return true;
            }

            // Do both have assembly names?
            if (this.asAssemblyName != null && that.asAssemblyName != null)
            {
                // Pointer compare.
                if (this.asAssemblyName == that.asAssemblyName)
                {
                    return true;
                }
            }

            // Do both have strings that equal each-other?
            if (this.asString != null && that.asString != null)
            {
                if (this.asString == that.asString)
                {
                    return true;
                }

                // If they weren't identical then they might still differ only by
                // case. So we can't assume that they don't match. So fall through...
                
            }

            // Do the names match?
            if (0 != String.Compare(Name, that.Name, StringComparison.OrdinalIgnoreCase))
            {
                return false;
            }

            // Do the versions match?
            if (Version != that.Version)
            {
                return false;
            }

            // Do the Cultures match?
            CultureInfo aCulture = CultureInfo;
            CultureInfo bCulture = that.CultureInfo;
            if (aCulture == null)
            {
                aCulture = CultureInfo.InvariantCulture;
            }
            if (bCulture == null)
            {
                bCulture = CultureInfo.InvariantCulture;
            }
            if (aCulture.LCID != bCulture.LCID)
            {
                return false;
            }

            // Do the PKTs match?
            byte[] aPKT = GetPublicKeyToken();
            byte[] bPKT = that.GetPublicKeyToken();

            // Some assemblies (real case was interop assembly) may have null PKTs.
            if (aPKT == null)
            {
                aPKT = new byte[0];
            }
            if (bPKT == null)
            {
                bPKT = new byte[0];
            }

            if (aPKT.Length != bPKT.Length)
            {
                return false;
            }
            for (int i = 0; i < aPKT.Length; ++i)
            {
                if (aPKT[i] != bPKT[i])
                {
                    return false;
                }
            }

            return true;
        }
        /// <summary>
        /// An implementation of compare that compares two base 
        /// names as quickly as possible.
        /// </summary>
        /// <param name="that"></param>
        /// <returns></returns>
        private int CompareBaseNameToImpl(AssemblyNameExtension that)
        {
            // Pointer compare, if identical then base names are
            // equal.
            if (this == that)
            {
                return 0;
            }
            // Do both have assembly names?
            if (this.asAssemblyName != null && that.asAssemblyName != null)
            {
                // Pointer compare.
                if (this.asAssemblyName == that.asAssemblyName)
                {
                    return 0;
                }

                // Base name compare.
                return String.Compare(this.asAssemblyName.Name, that.asAssemblyName.Name, StringComparison.OrdinalIgnoreCase);
            }

            // Do both have strings?
            if (this.asString != null && that.asString != null)
            {
                // If we have two random-case strings, then we need to compare case sensitively.
                return CompareBaseNamesStringWise(this.asString, that.asString);
            }

            // Fall back to comparing by name. This is the slow path.
            return String.Compare(this.Name, that.Name, StringComparison.OrdinalIgnoreCase);
        }
        /// <summary>
        /// Compare two base names as quickly as possible.
        /// </summary>
        /// <param name="that"></param>
        /// <returns></returns>
        internal int CompareBaseNameTo(AssemblyNameExtension that)
        {
            int result = CompareBaseNameToImpl(that);
#if DEBUG
            // Now, compare to the real value to make sure the result was accurate.
            AssemblyName a1 = this.asAssemblyName;
            AssemblyName a2 = that.asAssemblyName;
            if (a1 == null)
            {
                a1 = new AssemblyName(this.asString);
            }
            if (a2 == null)
            {
                a2 = new AssemblyName(that.asString);
            }

            int baselineResult = String.Compare(a1.Name, a2.Name, StringComparison.OrdinalIgnoreCase);
            Debug.Assert(result == baselineResult, "Optimized version of CompareBaseNameTo didn't return the same result as the baseline.");
#endif
            return result;
        }
        /// <summary>
        /// Compare one assembly name to another.
        /// </summary>
        /// <param name="that"></param>
        /// <returns></returns>
        internal int CompareTo(AssemblyNameExtension that)
        {

            // Are they identical?
            if (this.Equals(that))
            {
                return 0;
            }

            // Are the base names not identical?
            int result = CompareBaseNameTo(that);
            if (result != 0)
            {
                return result;
            }

            // We need some collating order for these, alphabetical by FullName seems as good as any.
            return String.Compare(this.FullName, that.FullName, StringComparison.OrdinalIgnoreCase);
        }
        /// <summary>
        /// Compare two assembly names for equality.
        /// </summary>
        /// <param name="that"></param>
        /// <returns></returns>
        internal bool Equals(AssemblyNameExtension that)
        {
            // Pointer compare.
            if (this == that)
            {
                return(true);
            }

            // Do both have assembly names?
            if (this.asAssemblyName != null && that.asAssemblyName != null)
            {
                // Pointer compare.
                if (this.asAssemblyName == that.asAssemblyName)
                {
                    return(true);
                }
            }

            // Do both have strings that equal each-other?
            if (this.asString != null && that.asString != null)
            {
                if (this.asString == that.asString)
                {
                    return(true);
                }

                // If they weren't identical then they might still differ only by
                // case. So we can't assume that they don't match. So fall through...
            }

            // Do the names match?
            if (0 != String.Compare(Name, that.Name, StringComparison.OrdinalIgnoreCase))
            {
                return(false);
            }

            // Do the versions match?
            if (Version != that.Version)
            {
                return(false);
            }

            // Do the Cultures match?
            CultureInfo aCulture = CultureInfo;
            CultureInfo bCulture = that.CultureInfo;

            if (aCulture == null)
            {
                aCulture = CultureInfo.InvariantCulture;
            }
            if (bCulture == null)
            {
                bCulture = CultureInfo.InvariantCulture;
            }
            if (aCulture.LCID != bCulture.LCID)
            {
                return(false);
            }

            // Do the PKTs match?
            byte[] aPKT = GetPublicKeyToken();
            byte[] bPKT = that.GetPublicKeyToken();

            // Some assemblies (real case was interop assembly) may have null PKTs.
            if (aPKT == null)
            {
                aPKT = new byte[0];
            }
            if (bPKT == null)
            {
                bPKT = new byte[0];
            }

            if (aPKT.Length != bPKT.Length)
            {
                return(false);
            }
            for (int i = 0; i < aPKT.Length; ++i)
            {
                if (aPKT[i] != bPKT[i])
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// This is an assembly resolution handler necessary for fixing up types instantiated in different
        /// AppDomains and loaded with a Assembly.LoadFrom equivalent call. See comments in TaskEngine.ExecuteTask
        /// for more details.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        /// <owner>lukaszg</owner>
        internal Assembly ResolveAssembly(object sender, ResolveEventArgs args)
        {
            // Is this our task assembly?
            if (taskAssemblyFile != null)
            {
                if (File.Exists(taskAssemblyFile))
                {
                    try
                    {
                        AssemblyNameExtension taskAssemblyName = new AssemblyNameExtension(AssemblyName.GetAssemblyName(taskAssemblyFile));
                        AssemblyNameExtension argAssemblyName = new AssemblyNameExtension(args.Name);

                        if (taskAssemblyName.Equals(argAssemblyName))
                        {
                            return Assembly.UnsafeLoadFrom(taskAssemblyFile);
                        }
                    }
                    // any problems with the task assembly? return null.
                    catch (FileNotFoundException )
                    {
                        return null;
                    }
                    catch (BadImageFormatException )
                    {
                        return null;
                    }
                }
            }

            // otherwise, have a nice day.
            return null;
        }