Convert an object that implements the interface into its own interface

Asked

Viewed 469 times

2

I made the following code:

using System;

public class Program
{
    public static void Main()
    {
        //Este método funciona
        Metodo(new ClasseTeste(){ Obj = new Registro(){ Nome = "Nome Teste"}});

        //Este não
        Metodo2(new ClasseTeste(){ Obj = new Registro(){ Nome = "Nome Teste2"}});

        //Este não          
        Metodo3(new ClasseTeste(){ Obj = new Registro(){ Nome = "Nome Teste3"}});

    }


    public static void Metodo<T>(IBase<T> parametro) where T: class,IRegistro
    {
        string nome = parametro.Obj.Nome;
        Console.WriteLine(nome);
    }

    public static void Metodo2(IBase<IRegistro> parametro)
    {
        string nome = parametro.Obj.Nome;
        Console.WriteLine(nome);
    }

    public static void Metodo3(Teste<IRegistro> parametro)
    {
        string nome = parametro.Obj.Nome;
        Console.WriteLine(nome);
    }
}

Registering:

public interface IRegistro
{
    string Nome {get;set;}
}

public class Registro : IRegistro
{
    public string Nome {get;set;}
}

Generic interface and implementation:

public interface IBase<T> where T : class
{
    T Obj {get;set;}
}

public abstract class Teste<T> : IBase<T> where T : class, IRegistro
{
    public T Obj {get;set;}
}

public class ClasseTeste : Teste<Registro>
{

}

The First Method Metodo works, the other two don’t.

The following error is returned:

Cannot convert ClasseTeste to IBase<IRegistro>

Question:

Because I cannot convert an object that implements the interface into its own interface ?

I put in the Dotnetfiddle

Edit:

After reading about Variance in generic interfaces (C#)

I changed the code to a covariant interface:

using System;

public class Program
{
    public static void Main()
    {

        Metodo(new ClasseTeste(){ Obj = new Registro(){ Nome = "Teste 1"} });

        Metodo2(new ClasseTeste(){ Obj = new Registro(){ Nome = "Teste 2"} });

        //Metodo3(new ClasseTeste());

    }


    public static void Metodo<T>(IBase<T> parametro) where T: class,IRegistro
    {
        string nome = parametro.GetObj().Nome;
        Console.WriteLine(nome);
    }

    public static void Metodo2(IBase<IRegistro> parametro)
    {
        string nome = parametro.GetObj().Nome;
        Console.WriteLine(nome);
    }

    public static void Metodo3(Teste<IRegistro> parametro)
    {
        string nome = parametro.GetObj().Nome;
        Console.WriteLine(nome);
    }
}

public interface IRegistro
{
    string Nome {get;set;}
}

public class Registro : IRegistro
{
    public string Nome {get;set;}
}


public interface IBase<out T> where T : class, IRegistro
{
    //T Obj{get;set;} //Erro (O Parametro T precisa ser invariante. T é Covariante
    T GetObj ();

    //void MetodoX(T obj); //Erro (O Parametro T precisa ser invariante. T é Covariante
}

public abstract class Teste<T> : IBase<T> where T : class, IRegistro
{
    public T Obj {get;set;}

    public T GetObj ()
    {
        return this.Obj;
    }
}

public class ClasseTeste : Teste<Registro>
{

}

Dotnetfiddle

The Method that waits IBase<IRegistro> now accept ClasseTeste, but on the interface I cannot declare properties or methods with generic type parameters.

1 answer

3


If you change this line it works:

public class ClasseTeste : Teste<IRegistro>

Another possibility is to make the parameters of Metodo2() and Metodo3() are:

IBase<Registro>

I put in the Github for future reference.

There is no variance in generic types. So you cannot accept IRegistro and send Registro as it does with "simple" types, ie, Teste<Registro> is not derived from Teste<IRegistro>, only Registro is derived from IRegistro.

When you use the T we’re not talking about inheritance, just parametric polymorphism, the compiler creates an indirect to access the actual instance. When you use IBase<IRegistro> it will attempt to access an object IRegistro that doesn’t exist, so it can only be the IBase<Registro>. Unless you say you want the interface in the specific type declaration, then the compiler knows there may be an inheritance in the generic type.

Something that many don’t understand that using a type makes any access to the object only possible in members of that type. Experience receiving any object like object and try to access a member of that object other than the public members of the Object. It doesn’t. Everything is there, you know that, but the compiler doesn’t. It can only guarantee the security of types if you programmer ensure that only access members of type Object. And the way to ensure that for the compiler is not using (it does not let use).

So when you say you’re gonna get Registro but passes a IRegistro nothing guarantees that the object that is certainly a IRegistro be a Registro, can be a Registro2 that conforms to IRegistro, but it is not the same as Registro. Teste<> can access any members of Registro, but if he gets one Registro2 who does not have any member who Registro will give error and will break security of types.

I know, you know everything will be okay, we’re seeing this in the code, a compiler that only manages monolithic executable by analyzing every source that generates it can do this, despite it being a complex and expensive operation, but a normal compiler who does not have this guarantee has no way of knowing if it is safe.

  • "Então quando você diz que vai receber Registro mas passa um IRegistro nada garante que o objeto que é certamente um IRegistro seja um Registro" It wouldn’t be the other way around IRegistro and step one Registro. If Registro implements IRegistro should not be guaranteed?!

  • I understood about the variance, I read on this material: https://docs.microsoft.comin-Generic-interfaces and changed the code so that it accepts the conversion of types with a covariant interface, but I cannot declare properties and methods that receive generic type parameters. (I edited the question)

  • My intention was to have a class that was not generic, receiving a generic object as a parameter, but it was not possible. The definition of covariance that I was able to do didn’t meet me either. I ended up doing the generic class as well. Thank you for your attention =]

Browser other questions tagged

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