C# Cannot convert from class to interface [duplicate] - c#

This question already has answers here:
Cannot convert type via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
(3 answers)
Closed 2 years ago.
I am new to using interfaces, but after reading up on it, I thought the idea of interfaces was that a class derived from an interface would be accepted anywhere the interface was accepted. Here's my code:
public interface IPersonOfInterest
{
//code requiring certain info to exist
}
public abstract class PersonOfInterest
{
public string[] GetBigPersonsInfo(List<IPersonOfInterest> FromList)
{
//code to gather a list of info that is guaranteed to be in any IPersonOfInterest
return new string[] { };
}
}
public class BigDonors : PersonOfInterest, IPersonOfInterest
{
public List<BigDonors> SuchDonors = new List<BigDonors>();
public void GimmeDemInfos()
{
string[] GetInfo = GetBigPersonsInfo(SuchDonors); //<-- compiler error here
}
}
As you can see, BigDonors is derived from the IPersonOfInterest interface. So why does it give a compiler error, saying a list of BigDonor cannot be converted to list of IPersonOfInterest? I understand that they aren't the same thing. I think I know what I'm trying to do here, but it isn't letting me do it.
EDIT: My question was quickly marked as already answered, however, the answer provided only explains the problem but doesn't really give a solution. So I'm editing this question with my solution:
For my particular case, I don't need to be able to add donors to the list, at least not in the abstract method. So Andrew Shepherd's link revealed that the problem was that, although my class could convert to the interface, a list cannot. So now I'm passing a read only list, which the compiler accepts:
public interface IPersonOfInterest
{
//code requiring certain info to exist
}
public virtual class PersonOfInterest : IPersonOfInterest
{
//Changed to IReadOnlyList<IPersonOfInterest>, instead of List<IPersonOfInterest>:
public string[] GetBigPersonsInfo(IReadOnlyList<IPersonOfInterest> FromList)
{
return new string[] { };
}
}
public class BigDonors : PersonOfInterest
{
public List<BigDonor> SuchDonors = new List<BigDonor>();
public void GimmeDemInfos()
{
//Added .AsReadOnly(), and it now compiles:
string[] GetInfo = GetBigPersonsInfo(SuchDonors.AsReadOnly());
}
}

You have identified the purpose of interfaces correctly. You need to use List<IPersonOfInterest>, because that complies with the description.
In short
BigDonor is inherited IPersonOfInterest, but List<BigDonor> was NOT inherited from List<IPersonOfInterest>. This means that you will need List<IPersonOfInterest> to be passed, but you will have the opportunity to add BigDonor elements to that List.

Related

Generic collection in a non-generic class [duplicate]

This question already has answers here:
C# - Multiple generic types in one list
(3 answers)
Closed 1 year ago.
I have the following class and interface
abstract class MyAbstractClass<T> where T : MyInterface
{
}
interface MyInterface {
}
I would like to have the following class:
class ContainerClass
{
private List<MyAbstractClass<T>> actions = new List<MyAbstractClass<T>>();
}
Where T is any class that extends MyInterface.
The important bit is here that is do not want to add a generic parameter to the ContainerClass and I need the exact implementation class, not the interface, so I can't just say:
private List<MyAbstractClass<MyInterface>> actions = new List<MyAbstractClass<MyInterface>>();
Long story short, I would like the following Java code in C#:
public class ContainerClass {
private List<MyAbstractClass<? extends MyInterface>> list = new ArrayList<>();
}
abstract class MyAbstractClass<T extends MyInterface> {
}
interface MyInterface {
}
Is possible in C#?
EDIT:
To clarify the question, let's see the below code piece:
abstract class GameAction<T> where T : IGameEntity
{
protected T Subject;
public GameAction(T subject)
{
Subject = subject;
}
public abstract bool Run();
}
class ActionRunner {
private List<GameAction<T>> actions = new List<GameAction<T>>();
public void RunAll() {
foreach (GameAction<T> action in actions) {
action.Run();
}
}
}
My goal here is to have different implementation classes of GameAction, each should be parameterized with different implementations of IGameEntity. IGameEntity can be considered now as marker interface (it has some methods, but they don't matter here), I just use it to enforce the type of Subject and to avoid repeated casting in the implementation classes. The member Subject can be anything, it can do anything in the Run method of the child classes.
What you ask for is not possible in C# because unfortunately only interfaces are allowed to have variant type parameters. As you said, in Java you would be able to declare a covariant variable, but in .net, due to various design decisions, you cant.
The only choice you have is to create a new interface
public interface MyAbstractClassWhenInReadOnlyList<out T>
{
T Method1();
void Method2(out T result);
...
}
and have your MyAbstractClass implement that interface.
There are some other choices, but they boil down to this, just in various guises. There is no way to access or use an object with a type variable without knowing the exact type that was used to construct the object. You must have a class without a type variable to use it (This includes reflection) or have an interface with the appropriate variance.
Please be aware that this has noting to do with Java's wild-card syntax nor the use-site vs declarations site variance syntax. These are both just notations used by the two programming languages to express an idea to the type checker.
Ultimately it comes down to static variables.
If a method accesses the List< int >.count variable vs the List< String > variable then it better be the correct value. In Java, static variables are associated with the "raw class", eg the type "List< ? extends Object >. In C# there are two variables, one associated with each set of type parameters.
Because Interfaces are unable to have static variables, there is no way that a static variable could be access incorrectly.

Check if object implements a specific generic interface [duplicate]

This question already has answers here:
How to determine if a type implements a specific generic interface type
(14 answers)
Check if a type implements a generic interface without considering the generic type arguments
(2 answers)
Closed 1 year ago.
Background
My code base currently has the following interfaces and classes:
// Both DisplayValue _classes_
public class DisplayValue<T>
{
public T Value { get; set; }
}
public class DisplayValue : DisplayValue<object> {}
// Both IValueWidget _interfaces_
public interface IValueWidget<T>
{
DisplayValue<T> Value { get; set; }
}
public interface IValueWidget: IValueWidget<object>
{
new DisplayValue Value { get; set; }
}
// the BaseWidget all other widgets implement
public interface IBaseWidget
{
public string Name { get; set; }
}
The code base also has a bunch of Widgets, all of which implement IBaseWidget. Some also implement IValueWidget or IValueWidget<T>, which leads me to my problem.
Problem
Say I have the following method:
public T2 DoStuff<T2>(T2 widget) where T2 : IBaseWidget
{
// this should check if the widget is the correct type
if (widget is IValueWidget)
{
}
}
In that method, I would like to have the condition work with either IValueWidget or any generic version of IValueWidget. I don't care whatsoever what the type of T is, only that the given T2 can be treated as such.
Also worth mentioning, literally no types other than the ones provided above are known at compile time. Everything must work at runtime.
In Java, I could do something like this but obviously C# does not have wildcards.
public T2 DoStuff<T2 extends IBaseWidget>(T2 widget) {
if (widget instanceof IValueWidget<?>) {
}
}
Notes
As far as I can tell, this is not actually a duplicate. Please don't flag it as such if you're referring to any of these, as they are similar but definitely not the same:
Check if object implements specific generic interface
Wildcard equivalent in C# generics
Get interfaces implemented by class

Generic type arguments inside generic constraints [duplicate]

This question already has answers here:
how to do nested generic classes (if that's the appropriate name) in csharp
(3 answers)
Closed 6 years ago.
I want to create a class that has a generic type argument which has a constraints to be a subclass of another generic class.
Example:
public class SomeGeneric<T> where T : new()
{
T CreateItem() => new T();
}
This class I want to create. Note: I do not want client of this class to specify the inner type argument twice:
public class TheClass<TGeneric> where TGeneric : SomeGeneric<T>, new()
{
public T Item {get; private set;}
public void TheClass
{
var instance = new TGeneric(); // this is possible because of the new() restriction
Item = instance.CreateItem();
}
}
This could then be used as follows:
class AnotherClass
{
}
class Client : TheClass<SomeGeneric<AnotherClass>>
{
public void SomeMethod()
{
var theInstanceOfAnotherClass = this.Item;
// Do stuff with it
}
}
As far as I can tell, this is not possible since it complains on this line that T is not known:
public class TheClass<TGeneric> where TGeneric : SomeGeneric<T>, new()
The workaround would be to do as follows:
public class TheClass<T, TGeneric> where TGeneric : SomeGeneric<T>, new()
But that would mean that the client has to do this:
public class Client : TheClass<AnotherClass, SomeGeneric<AnotherClass>>
I want to avoid duplicating the inner type argument. Is this possible?
I don't think this is possible. This question addresses the same situation.
This blurb from MSDN also states that it's not allowed, unlike in C++. I'm not sure if there's a reason for this limitation.
In C#, a generic type parameter cannot itself be a generic, although constructed types can be used as generics. C++ does allow template parameters.
I think you will have to rework your class in some way to use a generic object, or else just live with the duplicate type argument.
Does this work or even resemble what you want?
public SomeClass<TGeneric<T>> where TGeneric<T> : SomeGeneric<T>

C# Generic class as parameter with same T as called method of generic class

I would like call:
Question<Entity> question =
Question<Entity>.Create(
Choice.Create().
AddFollowUpQuestion(Question.Create()).
AddFollowUpQuestion(Question.Create()),
Choice.Create()
);
But the best C# allows me to do is:
Question<Entity> question =
Question<Entity>.Create(
Choice<Entity>.Create().
AddFollowUpQuestion(Question<Entity>.Create()).
AddFollowUpQuestion(Question<Entity>.Create()),
Choice<Entity>.Create()
);
I am trying to clean some code up, basically just adding syntactic sugar so some definitions I have to make a lot of are easier to read.
Both intelisense and the compiler know they are expecting the parameter to be of type Choice because it is a method of the generic class. But it still requires me to type out the type of T for the passed argument.
A bit more abstract: I am trying to create a top level generic class in which all properties which are also generic types will be using the same type for T.
Can anyone help me solve this puzzle? Or at least explain me why I have to type the same Type over and over again?
Simplified class definitions:
public class Question<T> where T : Entity
{
public static Question<T> Create(params Choice<T>[] choices)
{
return new Question<T>
{
Choices = choices
};
}
private Choice<T>[] Choices { get; set; }
}
public class Choice<T> where T : Entity
{
public static Choice<T> Create()
{
return new Choice<T>();
}
public Choice<T> AddFollowUpQuestion(Question<T> followUpQuestion)
{
FollowUpQuestions.Add(followUpQuestion);
return this;
}
private static List<Question<T>> FollowUpQuestions { get; set; }
}
public abstract class Entity
{
}
C# can infer the method that you want to call based on the type of a parameter, but it cannot infer the type of the class on which to call a method that produces a parameter of the required type: the "type inference magic" goes only one way.
Essentially, you giving the compiler Choice.Create() expression and the fact that its result is being passed to a method expecting Choice<Entity>, and asking it to deduce that Choice is actually a generic type (despite the fact that there may be a non-generic Choice in the system), and it has a Create() method that returns Choice<T>. Although the compiler could possibly do it, implementation would be expensive, and could potentially be a breaking change.
However, you can make a generic helper method that would provide the same T to multiple classes, like this:
static Question<T> MakeQuestion<T>() {
return Question<T>.Create(Choice<T>.Create());
}
Now you can call
Question<Entity> question = MakeQuestion<Entity>();
and pass the type parameter only once.
Edit: As far as the more elaborate example from your edit is concerned, you should be able to shorten the API by introducing a factory that is generic on Entity, and lets you create questions, follow-ups, etc.
class QuestionFactory<T> {
public Question<T> CreateQuestion() {
...
}
public Choice<T> CreateChoice() {
...
}
}
Now you can do this:
var qf = new QuestionFactory<Entity>();
var question = qf.CreateQuestion(
qf.CreateChoice().
AddFollowUpQuestion(qf.CreateQuestion()).
AddFollowUpQuestion(qf.CreateQuestion()),
qf.CreateChoice()
);
A common thing to do is to create non-generic classes for the factory method:
public static class Question {
public static Question<T> Create<T>(Choice<T> choice) {
return Question<T>.Create(choice);
}
}
...
Question<Entity> question = Question.Create(Choice<Entity>.Create());
One way is to change Question.Create() to not expect a Choice to be provided, rather it creates the Choice itself. It makes the code a little simpler and you can achieve your goal.
public class Question<T> where T : Entity
{
public static Question<T> Create()
{
return new Question<T>
{
Choice = Choice<T>.Create()
};
}
private Choice<T> Choice { get; set; }
}
public class Choice<T> where T : Entity
{
public static Choice<T> Create()
{
return new Choice<T>();
}
}
public abstract class Entity
{
}
Depending on the context, this can be a positive change as the responsibility of creation of a Choice is moved to the Question, in other words you abstract the callers of Question.Create() from the hassle of creation of Choice.
On the other hand, it increases the coupling of Question and Choice.
Which one is prefered, depends on the rest of the architecture.
Of course, I assumed that T is really needed in Choice.

How can I work around Type.IsAssignableFrom not working with inherited interfaces?

I've made a test case to illustrate the problem I've run into.
The first assert passes, but the second and third both fail.
Is there a way to check either of the two failing conditions k in a different way that will work? It would be OK if it's not terribly fast as I intend to cache the results on a per-type basis.
public interface IParentInterface
{
}
public interface IChildInterface : IParentInterface
{
}
public class ParentClass<T> where T: IParentInterface
{
}
public class ChildClass : ParentClass<IChildInterface>
{
}
public class TestClass
{
public ChildClass Property { get; set; }
}
[TestFixture]
public class ScratchPad
{
[Test]
public void Assignabl()
{
var tc = new TestClass();
var tct = tc.GetType();
var pi = tct.GetProperty("Property");
Assert.IsNotNull(pi);
Assert.IsTrue(typeof(ParentClass<IChildInterface>).IsAssignableFrom(pi.PropertyType));
Assert.IsTrue(typeof(ParentClass<>).IsAssignableFrom(pi.PropertyType));
Assert.IsTrue(typeof(ParentClass<IParentInterface>).IsAssignableFrom(pi.PropertyType));
}
}
It is by design that your second assertion fails. When you write
public class ParentClass<ParentInterface>
it actually means that "ParentInterface" is now a symbol for a type argument (doing that is so confusing that, indeed, it totally confused you).
Writing
public class ChildClass : ParentClass<ChildInterface>
then sets yout type argument (yeah, the one named "ParentInterface") to the type ChildInterface. Hence, Childclass is only assignable to ParentClass<ChildInterface>.
Lastly, you should ensure that you follow conventions when definining type arguments, it will confuse you a lot less, e.g.
public class ParentClass<T>
marking interfaces with "I" will also greatly enhance understanding, e.g.
interface IParent { }
interface IChild : IParent { }
I suspect that that which you want is not possible until we get c# 4.0:
Parent<IChild>
is not assignable to
Parent<IParent>
There is currently no co/contravariance for generics.
Isn't this the covariance/contravariance thing?
Then it's just something C# currently does not support, but C# 4.0 might.
You can't, because C# 3.0 does not support variance of this kind. In C# 4.0, you should be able to.
Using another example, say you had a List<ParentInterface>, and could assign it to a List<ChildInterface>:
List<ParentInterface> parentList = List<ParentInterface>();
List<ChildInterface> childList = parentList;
The problem is that the internal storage for parentList is for ParentInterface types. If you derived another interface from ChildInterface:
public interface ParentInterface2 : ChildInterface {}
And then tried to add it to childList like so:
childList.Add(new ParentInterface2Implementation());
You would get an exception, since childList is really a List<ParentInterface> and can only store implementations of ParentInterface, which ParentInterface2 is not.

Categories