GalRoimi
GalRoimi

Reputation: 37

Implementing interface properties in interfaces

I need to create a dll file which contains all the interfaces of the classes but doesn't contain any class. Because I use these interfaces for a lot of classes it's must be like that:

public interface IClassA
{
    string Word { get; }
}

public interface ITest<TClassA> where TClassA : IClassA
{
    TClassA A { get; }
}

Example of two classes that implements these interfaces the way I want:

public class ClassA : IClassA
{
    public string Word
    {
        get;
        private set;
    }

    public string Sentence
    {
        get;
        private set;
    }

    public ClassA(string word, string sentence)
    {
        this.Word = word;
        this.Sentence = sentence;
    }
}

public class Test : ITest<ClassA>
{
    public ClassA A
    {
        get;
        private set;
    }

    public Test(ClassA a)
    {
        this.A = a;
    }
}

And I want to do something like that in the main program:

public static void Main(string[] args)
{
    ClassA a = new ClassA("hey", "hey world!");
    Test t = new Test(a);

    Print((ITest<IClassA>)t);        
}

public static void Print(ITest<IClassA> t)
{
    Console.WriteLine(t.A.Word);
}

But this casting: (ITest<IClassA>)t makes a run time error. How can I solve it? thanks!

Upvotes: 0

Views: 104

Answers (3)

Dragan Radovac
Dragan Radovac

Reputation: 11

Generics on ITest should be more arbitrary

ITest<T> { T? I { get } }

That's all well and good but whenever we want to use ITest<T> we need to implement it in a class that declares our type of T. The number of disparate classes can grow very quickly. What is needed here is more generics. Lets create a generic type that takes T an also implements ITest<T>. We will call it Test<T>

class Test<T>(T i) : ITest<T> { public T I => i; }

To be honest ITest<T> does not need to be implemented by Test<T>. I referenced it as it was part of the question although using the code above is no different than using the code below. We can now just use Test<T> without the interface

class Test<T>(T i) { public T I => i; }

Interfaces with generics on the most part I have found not to be a good idea. I can't chew gum and walk at the same time so the added confusion of generics with interfaces is something I can do without.

Now we can pass in any type without being bound to an implementation. The next example shows how to use our new generic type Test<T> and how simple it is to now print the properties of a, b and c to the console

var a = new Test<IClassA>(new ClassA("word", "sentence"));
Console.WriteLine($"IClassA !!! {a.I.Word}, {((ClassA)a.I).Sentence}");

var b = new Test<ClassB>(new ClassB("quote", "paragraph", "footer"));
Console.WriteLine($"ClassB !!! {b.I.Quote}, {b.I.Paragraph}, {b.I.Footer}");

var c = new Test<int>(111);
Console.WriteLine($"int !!! {c.I}");

Below is the complete example code which uses an interface, class and primitive type with Test<T>

namespace Application;

class Program
{
    class Test<T>(T i) { public T I => i; }

    interface IClassA { string? Word { get; } }
    class ClassA(string? word, string? sentence) : IClassA
    {
        public string? Word => word;
        public string? Sentence => sentence;
    }

    class ClassB(string? quote, string? paragraph, string? footer)
    {
        public string? Quote => quote;
        public string? Paragraph => paragraph;
        public string? Footer => footer;
    }

    static void Main()
    {
        var a = new Test<IClassA>(new ClassA("word", "sentence"));
        Console.WriteLine($"IClassA !!! {a.I.Word}, {((ClassA)a.I).Sentence}");

        var b = new Test<ClassB>(new ClassB("quote", "paragraph", "footer"));
        Console.WriteLine($"ClassB !!! {b.I.Quote}, {b.I.Paragraph}, {b.I.Footer}");

        var c = new Test<int>(111);
        Console.WriteLine($"int !!! {c.I}");
    }
}

Upvotes: 0

Jan K&#246;hler
Jan K&#246;hler

Reputation: 6030

The Test-class implements the concrete ClassA (public class Test : ITest<ClassA>).

So you're trying to cast an ITest<ClassA> to ITest<IClassA> which obviously fails.

If you let the Test-class implement IClassA, the cast works:

public class Test : ITest<IClassA>
{
    public IClassA A
    {
        get; private set;
    }

    public Test(IClassA a)
    {
        this.A = a;
    }
}

Upvotes: 1

Thomas Levesque
Thomas Levesque

Reputation: 292685

You should declare Test as

public class Test : ITest<IClassA>

instead of ITest<ClassA>.

Or declare ITest<TClassA> to be covariant on TClassA:

public interface ITest<out TClassA> where TClassA : IClassA

Upvotes: 2

Related Questions