using System; using System.Diagnostics; using System.Globalization; using LibGit2Sharp.Core; namespace LibGit2Sharp { /// /// A base class for things that wrap a (branch, tag, etc). /// /// The type of the referenced Git object. [DebuggerDisplay("{DebuggerDisplay,nq}")] public abstract class ReferenceWrapper : IEquatable>, IBelongToARepository where TObject : GitObject { /// /// The repository. /// protected readonly Repository repo; private readonly Lazy objectBuilder; private static readonly LambdaEqualityHelper> equalityHelper = new LambdaEqualityHelper>(x => x.CanonicalName, x => x.TargetObject); private readonly string canonicalName; /// /// Needed for mocking purposes. /// protected ReferenceWrapper() { } /// The repository. /// The reference. /// A function to construct the reference's canonical name. protected internal ReferenceWrapper(Repository repo, Reference reference, Func canonicalNameSelector) { Ensure.ArgumentNotNull(repo, "repo"); Ensure.ArgumentNotNull(reference, "reference"); Ensure.ArgumentNotNull(canonicalNameSelector, "canonicalNameSelector"); this.repo = repo; canonicalName = canonicalNameSelector(reference); objectBuilder = new Lazy(() => RetrieveTargetObject(reference)); } /// /// Gets the full name of this reference. /// public virtual string CanonicalName { get { return canonicalName; } } /// /// Gets the name of this reference. /// public virtual string Name { get { return Shorten(); } } /// /// Returns the , a representation of the current reference. /// /// The that represents the current reference. public override string ToString() { return CanonicalName; } /// /// Gets the this points to. /// protected TObject TargetObject { get { return objectBuilder.Value; } } /// /// Removes redundent leading namespaces (regarding the kind of /// reference being wrapped) from the canonical name. /// /// The friendly shortened name protected abstract string Shorten(); private TObject RetrieveTargetObject(Reference reference) { var directReference = reference.ResolveToDirectReference(); if (directReference == null) { return null; } var target = directReference.Target; if (target == null) { return null; } return repo.Lookup(target.Id); } /// /// Determines whether the specified is equal to the current . /// /// The to compare with the current . /// True if the specified is equal to the current ; otherwise, false. public bool Equals(ReferenceWrapper other) { return equalityHelper.Equals(this, other); } /// /// Determines whether the specified is equal to the current . /// /// The to compare with the current . /// True if the specified is equal to the current ; otherwise, false. public override bool Equals(object obj) { return Equals(obj as ReferenceWrapper); } /// /// Returns the hash code for this instance. /// /// A 32-bit signed integer hash code. public override int GetHashCode() { return equalityHelper.GetHashCode(this); } /// /// Tests if two are equal. /// /// First to compare. /// Second to compare. /// True if the two objects are equal; false otherwise. public static bool operator ==(ReferenceWrapper left, ReferenceWrapper right) { return Equals(left, right); } /// /// Tests if two are different. /// /// First to compare. /// Second to compare. /// True if the two objects are different; false otherwise. public static bool operator !=(ReferenceWrapper left, ReferenceWrapper right) { return !Equals(left, right); } private string DebuggerDisplay { get { return string.Format(CultureInfo.InvariantCulture, "{0} => \"{1}\"", CanonicalName, (TargetObject != null) ? TargetObject.Id.ToString(7) : "?"); } } IRepository IBelongToARepository.Repository { get { return repo; } } } }