A list of a guy can’t pass as a list of his 'higher' type?

Asked

Viewed 79 times

4

There are some entities in the application that I am developing that need to be sorted by a predefined routine.

Thinking about it was created contract class, called ElementoOrdenavel and all entities that can be ordered inherit from this class.

She exposes, a priori, only two members. Here is the class code.

public abstract class ElementoOrdenavel
{
    public int Id { get; set; }
    public int Ordem { get; set; }
}

Example of a class that inherits from this

public class Banner : ElementoOrdenavel
{
    public string Descricao { get; set; }
}

To facilitate my work, I made a method that receives a list of ElementoOrdenavel and does the work of ordination, thus

void Reorganizar(IEnumerable<ElementoOrdenavel> colecao, int[] idsOrdenados)
{
    for (int ordem = 0; ordem < idsOrdenados.Length; ordem++)
    {
        var elemento = colecao.First(m => m.Id == idsOrdenados[ordem]);
        elemento.Ordem = ordem + 1;
    }
}

And I tried to call this method

var banners = db.Banners.AsEnumerable();
Reorganizar(banners, ids);

And to my surprise, I got the mistake

cannot Convert from 'IEnumerable<Banner>' to 'IEnumerable<ElementoOrdenavel>'

A list of Banner nay is a list of ElementoOrdenavel?


Making a generic method works normally. Why?

void Reorganizar<T>(IEnumerable<T> colecao, int[] idsOrdenados) where T : ElementoOrdenavel
{
    for (int ordem = 0; ordem < idsOrdenados.Length; ordem++)
    {
        var elemento = colecao.First(m => m.Id == idsOrdenados[ordem]);
        elemento.Ordem = ordem + 1;
    }
}
  • How I hate this inheritance ;) I did not read it right, but I think it is a matter of variance: https://answall.com/q/32880/101 and https://answall.com/q/75097/101 and https://answall.com/a/56056/101 and https://en.stackoverflow.com/q/206278/101. Genericity gives you the guarantee that you will be okay.

  • The first only accepts IEnumerable<ElementoOrdenavel>, or has a dynamic polymorphism in the IEnumerable, but there is no polymorphism in its parameter. There, in C#, the only way to make the parameter of this polymorphic interface precise of generity.

  • I need to get a better look at the case before I answer, I’ll try as soon as I can

  • I don’t like the inheritance much either, but there would be no other way to fix the contract to make a unique method without using it.

1 answer

1


Covariance is the conversion of an object of the most specific type Banner in a more generic type ElementoOrdenavel. Operators may only be used in parameters of interfaces or delegates generic.

It could be done like this:

var banners = db.Banners.AsEnumerable();
IEnumerable<ElementoOrdenavel> elemento = banners;
Reorganizar(elemento , ids);

Or, if you use an interface to implement ElementoOrdenavel:

public interface IElementoOrdenavel
{
    int Id { get; set; }
    int Ordem { get; set; }
}
public abstract class ElementoOrdenavel: IElementoOrdenavel
{
    public int Id { get; set; }
    public int Ordem { get; set; }

}
public class Banner : ElementoOrdenavel
{
    public string Descricao { get; set; }
}

public class Teste
{
    public static void TesteReorganizar()
    {
        IEnumerable<Banner> a = new List<Banner>() { new Banner(){ Descricao="TESTE", Id = 1, Ordem = 0} };


        Reorganizar(a, new int[] { 1 });
    }

    public static void Reorganizar(IEnumerable<IElementoOrdenavel> colecao, int[] idsOrdenados)
    {

        for (int ordem = 0; ordem < idsOrdenados.Length; ordem++)
        {
            var elemento = colecao.First(m => m.Id == idsOrdenados[ordem]);
            elemento.Ordem = ordem + 1;
        }
    }
}

Or, since you don’t like to use inheritance, remove the class ElementoOrdenavel and the class Banner and others would directly inherit interface IElementoOrdenavel

Update:

I redid your code, now at home, and to my surprise it worked normally. It was then that I decided to check the version of . NET Framework.

You must be using version 3.5, which presented the same error, in the higher versions it is already possible to do this conversion directly, without any problem.

Researching the Documentation of the interface:

In version 3.5 or lower, the interface statement is like this:

public interface IEnumerable<T> : IEnumerable

Already from version 4.0, the statement is like this:

public interface IEnumerable<out T> : IEnumerable

Therefore, the covariance defined by the key out has only been implemented since version 4.0 of . NET Framework

  • Cool your answer. But, like, I want to know why. It’s solved.

  • I found more information and updated the reply @LINQ

  • 1

    You’re right, I’m using . NET 3.5 and had not even attempted it. Thanks.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.