Reputation: 37
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
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
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
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