Clodoaldo Neto
Clodoaldo Neto

Reputation: 125214

Check if List contains an instance equal to a given one

I don't want to loop through the list comparing each property. Something with this functionality:

class myClass
{
    public int I { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        List<myClass> l = new List<myClass>();

        myClass x = new myClass();
        x.I = 1;
        l.Add(x);

        myClass y = new myClass();
        y.I = 2;
        l.Add(y);

        myClass z = new myClass();
        z.I = 2;

        if (l.ContainsAnInstanceEqualTo(z))
            Console.WriteLine("Contains");

        Console.ReadLine();
    }
}

IMPORTANT: I have no control over the class and there are a few properties which should have the same value.

Upvotes: 2

Views: 6405

Answers (5)

Final Heaven
Final Heaven

Reputation: 134

public static class ObjectExtension
{
    #region Public Methods

    public static bool ExEquals<T>(this T obj, T objToCompare)
    {
        if (typeof(T) == typeof(string))
            return StringExtension.ExEquals(obj as string, objToCompare as string);
        return obj.Equals(objToCompare);
    }

    public static bool ExHasAllEquals<T>(this T obj, params T[] objArgs)
    {
        for (int index = 0; index < objArgs.Length; index++)
            if (ExEquals<T>(obj, objArgs[index]) == false) return false;
        return true;
    }

    public static bool ExHasEquals<T>(this T obj, params T[] objArgs)
    {
        for (int index = 0; index < objArgs.Length; index++)
            if (ExEquals<T>(obj, objArgs[index])) return true;
        return false;
    }

    public static bool ExHasNoEquals<T>(this T obj, params T[] objArgs)
    {
        return ExHasEquals<T>(obj, objArgs) == false;
    }

    public static bool ExHasNotAllEquals<T>(this T obj, params T[] objArgs)
    {
        for (int index = 0; index < objArgs.Length; index++)
            if (ExEquals<T>(obj, objArgs[index])) return false;
        return true;
    }

    public static bool ExIsNone(this object obj)
    {
        if (obj == null) return true;

        if (obj.Equals(DBNull.Value)) return true;

        return false;
    }

    public static bool ExNotEquals<T>(this T obj, T objToCompare)
    {
        return ExEquals<T>(obj, objToCompare) == false;
    }

    #endregion Public Methods
}


public static class StringExtension
{
    #region Public Methods

    public static bool ExContains(this string fullText, string value)
    {
        return ExIndexOf(fullText, value) > -1;
    }

    public static bool ExEquals(this string text, string textToCompare)
    {
        return text.Equals(textToCompare, StringComparison.OrdinalIgnoreCase);
    }

    public static bool ExHasAllEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index]) == false) return false;
        return true;
    }

    public static bool ExHasEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index])) return true;
        return false;
    }

    public static bool ExHasNoEquals(this string text, params string[] textArgs)
    {
        return ExHasEquals(text, textArgs) == false;
    }

    public static bool ExHasNotAllEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index])) return false;
        return true;
    }

    /// <summary>
    /// Reports the zero-based index of the first occurrence of the specified string
    /// in the current System.String object using StringComparison.InvariantCultureIgnoreCase.
    /// A parameter specifies the type of search to use for the specified string.
    /// </summary>
    /// <param name="fullText">
    /// The string to search inside.
    /// </param>
    /// <param name="value">
    /// The string to seek.
    /// </param>
    /// <returns>
    /// The index position of the value parameter if that string is found, or -1 if it
    /// is not. If value is System.String.Empty, the return value is 0.
    /// </returns>
    /// <exception cref="ArgumentNullException">
    /// fullText or value is null.
    /// </exception>
    public static int ExIndexOf(this string fullText, string value)
    {
        return fullText.IndexOf(value, StringComparison.OrdinalIgnoreCase);
    }

    public static bool ExNotEquals(this string text, string textToCompare)
    {
        return ExEquals(text, textToCompare) == false;
    }

    #endregion Public Methods
}

Upvotes: 0

Clodoaldo Neto
Clodoaldo Neto

Reputation: 125214

This is my try at creating an EqualityComparer that should compare public instance properties of any class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication2
{
    class MyClass
    {
        public int I { get; set; }
        public string S { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            HashSet<MyClass> hs = new HashSet<MyClass>(new SamePublicPropertiesInstance());

            MyClass x = new MyClass();
            x.I = 1;
            x.S = "1";
            hs.Add(x);
            MyClass y = new MyClass();
            y.I = 2;
            y.S = "1";
            hs.Add(y);
            MyClass z = new MyClass();
            z.I = 2;
            z.S = "1";
            hs.Add(z);

            foreach (MyClass m in hs)
            {
                Console.WriteLine("I: {0} S: {1}", m.I, m.S);
            }

            Console.ReadLine();
        }
    }
}

class SamePublicPropertiesInstance : EqualityComparer<object>
{
    public override bool Equals(object o1, object o2)
    {
        PropertyInfo[] pInfos = o1.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
        string pName;
        bool equal;
        MethodInfo methodInfo;

        foreach (PropertyInfo pInfo in pInfos)
        {
            pName = pInfo.Name.ToString();
            methodInfo = o1.GetType().GetProperty(pName).GetGetMethod();
            equal = methodInfo.Invoke(o1, null).ToString() 
                    == 
                    methodInfo.Invoke(o2, null).ToString();
            if (!equal) return false;
        }
        return true;
    }

    public override int GetHashCode(object o)
    {
        return 1.GetHashCode();
    }
}

Upvotes: 0

Kiley Naro
Kiley Naro

Reputation: 1769

You may be confusing some of the terminology here... In your example, even if Y and Z have the same values for I, they're not the same instance. If you are hoping to figure out whether or not their values are the same, you could either override the Object.Equals() method, or you could use Object.GetHashCode() method. You could even consider possibly using a Dictionary in some fashion.

If you are trying to determine whether or not the exact instance of the element that you're trying to add already exists in the list, you may want to consider looking at a HashSet.

Upvotes: 0

FishBasketGordo
FishBasketGordo

Reputation: 23132

Use the Contains method with a Predicate<myClass>:

if (l.Contains(item => item.I == z.I))
    Console.WriteLine("Contains");

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500055

You should make myClass implement IEquatable<myClass> (or at least override Equals(object)) and then just use:

if (l.Contains(z))

(You should also rename the class to follow .NET naming conventions...)

If you don't provide an Equals method, you've got to specify what sort of equality you're interested in somehow. You can do this via something like Find with a predicate:

var found = l.Find(c => c.I == z.I);
if (found != null)
{
    ...
}

Or using LINQ:

var any = l.Any(c => c.I == z.I);

but it would be better to override Equals if there is a natural sense of equality.

(List<T>.Contains won't use your implementation of GetHashCode, but you should implement it in line with your Equals method anyway...)

Upvotes: 8

Related Questions