agiro
agiro

Reputation: 2080

Interface reference that specifies I need an object implementing 2 or more interfaces

Let us say I have this overly simple code here:

class Person
{
    public int age;
    public string name;
    public Person(int age, string name)
    {
        this.age = age;
        this.name = name; 
    }
}
public class MySimpleDatabase
{
    List<Person> people;

    internal List<Person> People
    {
        get
        {
            if(people == null)
            {
                people = new List<Person>();
                people.Add(new Person(24, "ASD"));
                people.Add(new Person(35, "QWE"));
                people.Add(new Person(12, "MNB"));
            }
            return people;
        }
    }
}
public class ProcessPeopleConcrete
{
    public void WriteNames()
    {
        List<Person> people = new MySimpleDatabase().People;
        foreach (var person in people)
        {
            Console.WriteLine(person.name);
        }
    }
}
public class ProcessPeopleInterface
{
    public void WriteNames()
    {
        //question for here.
        IEnumerable<Person> people = new MySimpleDatabase().People;
        foreach (var person in people)
        {
            Console.WriteLine(person.name);
        }
    }
}

Here I have the concrete processor as well as the interface based one. Here the interface processor is more maintainable of course, but as far as I know

   //edited here to clarify

I can specify only one type for a variable that I require, in my case it is the IEnumerable<Person>.

What if I need something there that implements not one, but two interfaces at the same time, that have nothing to do with each other (one doesn't implement the other)?

So say I need any collection that has to implement both ICloneable and IEnumerator. In a comment it was put correctly that I could define another interface that implements both of them. But if I use pre-defined collections, I can't do that becuase then I won't be able to toss any of them as they obviously don't implement my custom made interface.

What sort of type would I specify in this case to my variable people (commented with "question here")? If there was a variable declaration like <IEnumerable, ICloneable> people; that would imaginarily mean I need something that implements both IEnumerable and ICloneable. But is there a language feature similar to that or it is what I said it is - imaginary only?

Upvotes: 2

Views: 51

Answers (2)

oneManArmin
oneManArmin

Reputation: 696

This might not exactly be what you are looking for, but here's something similar to you concept. I created a simple function accepting a Tuple of IEnumerable and IList, then you can feed arguments to it:

public static void Foo(Tuple<IEnumerable<int>, IList<int>> complex)
    {
        foreach (var item in complex.Item1)
        {
            Console.WriteLine(item.ToString());
        }

        complex.Item2.Add(9);

    }

A simple list:

 List<int> ints = new List<int>
  {
      1,
      3,
      5,
      7
   };

The function is then invoked by either first instantiating a separate variable, as I did, or writing the instantiation right into the Foo() function.

Tuple<IEnumerable<int>, IList<int>> tuple = Tuple.Create((ints as IEnumerable<int>), (ints as IList<int>));
Foo(tuple);

I'm also interested in a real solution though, provided that there is one.

Upvotes: 1

jgauffin
jgauffin

Reputation: 101140

As you have figured out, you cannot force classes to implement interfaces which they don't ;)

You have also noted that interfaces are used to solve a specific problem. In one case they solve how collections can be enumerated, and in the other case they solve how an object can be cloned.

From your question I take it that you want to be able to tell that the returned object solves both problems and you wonder how you can tell that in the method contract.

You do it by defining a new interface:

public interface ISuperClonableList<T> : IEnumerable<T>, IClonable
{
}

That's it.

If the list itself isn't clonable you need to wrap it in a new class which implements both interfaces. Pass the actual list as a constructor parameter and call it in every IEnumerable method implementation.

The problem with cloning interfaces is that they typically do not specify if it should be a deep or shallow clone. It's important to know that since it can cause large problems if the contained items are mutable.

Example generated from ReSharper:

public class MyListWrapper<T> : ISuperClonableList<T>
{
    private readonly ISuperClonableList<T> _innerList;

    public MyListWrapper(ISuperClonableList<T> innerList)
    {
        _innerList = innerList;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _innerList.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable) _innerList).GetEnumerator();
    }

    public void Add(T item)
    {
        _innerList.Add(item);
    }

    public void Clear()
    {
        _innerList.Clear();
    }

    public bool Contains(T item)
    {
        return _innerList.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _innerList.CopyTo(array, arrayIndex);
    }

    public bool Remove(T item)
    {
        return _innerList.Remove(item);
    }

    public int Count
    {
        get { return _innerList.Count; }
    }

    public bool IsReadOnly
    {
        get { return _innerList.IsReadOnly; }
    }

    public int IndexOf(T item)
    {
        return _innerList.IndexOf(item);
    }

    public void Insert(int index, T item)
    {
        _innerList.Insert(index, item);
    }

    public void RemoveAt(int index)
    {
        _innerList.RemoveAt(index);
    }

    public T this[int index]
    {
        get { return _innerList[index]; }
        set { _innerList[index] = value; }
    }
}

Upvotes: 1

Related Questions