Object oriented error [duplicate] - c#

This question already has answers here:
How to correctly cast a class to an abstract class when using type generics?
(4 answers)
Closed 4 years ago.
What is the reason for this code error:
Casting Deriving Class as Base Class
public class Program
{
private static void Main(string[] args)
{
BaseClass<IComparable> baseClass;
baseClass = DateTime.Now.Ticks == 100 ? new Age(110) : new Name("behroz");
Console.WriteLine(baseClass.Get());
Console.ReadKey();
}
}
public abstract class BaseClass<T> where T : IComparable
{
protected readonly T Data;
protected BaseClass(T data) => Data = data;
public abstract T Get();
}
public class Name : BaseClass<String>
{
public Name(string data) : base(data) { }
public override string Get() => "Name :" + Data;
}
public class Age : BaseClass<Int64>
{
public Age(Int64 data) : base(data) { }
public override Int64 Get() => 10 + Data;
}

You should listen to the compiler. You should be getting this error:
The type 'System.IComparable' cannot be used as type parameter 'T' in the generic type or method 'BaseClass'. There is no implicit reference conversion from 'System.IComparable' to 'System.IComparable'.
That's you're first issue.
So you could change the BaseClass<T> to be this: public abstract class BaseClass<T> where T : IComparable.
Bu now you have this error:
Type of conditional expression cannot be determined because there is no implicit conversion between 'Age' and 'Name'
That's because your DateTime.Now.Ticks == 100 ? new Age(110) : new Name("behroz") isn't making sure you're specifying a common type.
Now if I try to change it to DateTime.Now.Ticks == 100 ? (BaseClass<IComparable>)new Age(110) : (BaseClass<IComparable>)new Name("behroz") then I get these errors:
Cannot convert type 'Age' to 'BaseClass'
Cannot convert type 'Name' to 'BaseClass'
Now this is where it gets more interesting.
Just because Int64 is an IComparable it does not mean that BaseClass<Int64> is a BaseClass<IComparable>. It's not.
Same with BaseClass<String> and BaseClass<IComparable>.
You simply can't use BaseClass<IComparable> for the types Name and Age.

You are trying to initiate abstract class, which is wrong.
BaseClass baseClass;
baseClass = new Age(110);
Casting deriving class(i.e. BaseClass) as base class is causing this issue.
You can directly call the class based on your conditions.

Related

object oriented Casting error [duplicate]

This question already has answers here:
How to correctly cast a class to an abstract class when using type generics?
(4 answers)
Closed 4 years ago.
Casting Deriving Class as Base Class
I have a base abstract class which is generic and inherits from IComparable which is defined like below
public abstract class BaseClass<T> where T : IComparable
{
protected readonly T Data;
protected BaseClass(T data)
{
Data = data;
}
public abstract T Get();
}
Then I have defined a classe which inherits from this base class and has a specific generic type and is defined like below:
public class Name : BaseClass<String>
{
public Name(string data) : base(data)
{
}
public override string Get()
{
throw new NotImplementedException();
}
}
As generic type is string and string inherits from IComparable, I expect to be able to define new Name object with string value as generic type, but I get casting error for defining Name object like this:
BaseClass<IComparable> obj;
obj = new Name("behro0z");
and the error is
Error CS0029 Cannot implicitly convert type ConsoleApplication1.Name
to
ConsoleApplication1.BaseClass<System.IComparable> ConsoleApplication1
You're declaring a variable of type BaseClass<T>, and substitute T with IComparable.
That's valid, but that's not what your Name class is. That one derives from BaseClass<string>, not BaseClass<IComparable>, even though string implements IComparable.
You can either declare your variable obj to be of type BaseClass<string>, or the more derived type, Name.
Read up on covariance, C# Generics Inheritance Problem.

Error assigning class implementing generic interface to generic variable [duplicate]

This question already has answers here:
Generics and casting - cannot cast inherited class to base class
(3 answers)
Closed 5 years ago.
With reference to InvalidCastException on Generics, I have adapted the given answer for my own application. As an example:
public interface IData
{
string getValue();
}
public interface IController<in T> where T : IData
{
string formString(T data);
}
public class DataImplA : IData
{
public string getValue()
{
return "DataImplA";
}
}
public class ControllerImplA : IController<DataImplA>
{
public string formString(DataImplA data)
{
return "ControllerImplA, " + data.getvalue();
}
}
public class Program
{
private static IController<IData> controller;
public static void main(string[] args)
{
// Line with error
Program.controller = (IController<IData>)new ControllerImplA();
Console.WriteLine(Program.controller.formString(new DataImplA()));
}
}
During runtime, the indicated line will trigger
InvalidCastException: Unable to cast object of type 'ControllerImplA' to type 'IController`1[IData].
I tried changing to Program.controller = (IController<IData>)new ControllerImplA<DataImplA>(); but this results in the compilation error The non-generic type 'ControllerImplA' cannot be used with type arguments
I then tried changing the class definition to public class ControllerImplA<DataImplA> : IController<DataImplA> but then the new compilation error is:
The type 'DataImplA' cannot be used as type parameter 'T' in the generic type or method 'IController T'. There is no boxing conversion or type parameter conversion from 'DataImplA' to 'IData'.
I don't want to use public class ControllerImplA<T> : IController<T> because the constraint is that ControllerImplA can only use DataImplA, ControllerImplB can only use DataImplB and so on so forth.
How should I correct my original code?
In my opinion, Generic class is actually a placeholder for classes. By type "T", it creates different types/classes in runtime. Which means IController<IData> and IController<DataImplA> are totally different classes, they have no inheritance relationship.

Delegate "wrong return type"

On one hand I have the following delegate :
public delegate IBar FooDelegate(string str);
public delegate IBar FooDelegateWithRef(string str, IBar someBar);
On the other hand I have a generic class :
public class MyBaseClass
where T : IBar, new()
{
public FooDelegate myFunc;
public FooDelegateWithRef myFuncWithRef;
}
public class MyClass<T> : MyBaseClass
where T : IBar, new()
{
public MyClass()
{
myFunc = Foo; //"Wrong return type"
myFuncWithRef = FooWithRef; //"No overload...matches delegate"
}
public T Foo(string){ ... }
public T FooWithRef(string, IBar){ ... }
}
My problem is when I do the following :
FooDelegate fooRef = MyClassInstance.Foo;
I get a 'wrong return type' error. I understand that a delegate signature must match the method signature, but since the "where" instruction in the generic actually specify clearly T is IBar, why doesn't it work ?
So two questions in one :
- why the compiler refuse to consider that the method signature is matching ?
- more importantly, how can I make this work ? I would prefer a delegate-friendly solution rather than using Func for conventions reasons.
note : I tried looking around for an answer, yet I might have the wrong wording for the question, so feel free to slap me in the face If this has been answered before.
EDIT : As #Jonathon Chase pointed out, my sample code doesn't quite wraps the problem. A non-working example can be found here. Edited the code above to reflect the issue.
EDIT 2 : All the answers where very informative to me, thanks a lot for your time. I would have checked all three if I could !
The "wrong return type" error is because variance does not support value types. So a class implementing IBar can be converted, while a struct implementing won't be:
class RefTypeBar : IBar {}
struct ValueTypeBar : IBar {}
FooDelegate f1 = new MyClass<RefTypeBar>().Foo; // This works
FooDelegate f2 = new MyClass<ValueTypeBar().Foo; // Fails - wrong return type
The error is generated inside of MyClass<T> because T could be a struct, so the complier can't guarantee that that Foo can be assigned a FooDelegate. If you add a class constraint to MyClass<T> the code will compile.
public class MyClass<T> : MyBaseClass where T : class, IBar, new()
There must be something else going on with your example here. I'm currently able to compile and run the following example and receive the expected result:
public class Program
{
public static void Main()
{
var x = new MyClass<Bar>();
FooDelegate test = x.Foo;
test("Do It");
}
public delegate IBar FooDelegate(string str);
public interface IBar { }
public class Bar : IBar { }
public class MyClass<T> where T : IBar, new()
{
T item;
public T Foo(string input) { Console.WriteLine(input); return item; }
}
}
DotNetFiddle
At least in your DotNetFiddle example, you can make the first assignment to funcA possible by changing the generic constraint to where T: Item, new().
In the second assignment, the delegate uses type T both as return type and as parameter type. I believe this leads to the sometimes strange effects of covariance and contravariance (MSDN about Co/Contravariance):
Let us assume that a generic instance uses a type class SubItem : Item {...}
for type parameter T of your class TypedFactory<T>.
It is ok to use SubItem as return type, since the return type will still be of (sub)type Item, and the delegate variable (e.g. funcA) still "satisfies" the contract described by the declaration of the delegate type.
But what happens if we used SubItem as a parameter type? The delegate variable (e.g. funcB) could no longer be called in each context which the declaration of the delegate type promises, e.g. Item blubb; factory.funcB("I am alive too", blubb) is not possible - the types do not match, since blubb is not of type SubItem. Since this might happen, the compiler has to complain here.
Maybe it is an option for you to make the delegates generic?
using System;
public interface IItem
{
string id {get;set;}
}
public class Item : IItem
{
public string id{get;set;}
}
public class BaseFactory<T>
where T: IItem, new()
{
public DelegateHolder.MakeWithID<T> funcA;
public DelegateHolder.MakeWithIDAndOther<T> funcB;
}
public class TypedFactory<T> : BaseFactory<T>
where T : IItem, new()
{
public TypedFactory()
{
funcA = makeNew;
funcB = makeNewFromOther;
}
public T makeNew(string itemId)
{
T _item = new T();
_item.id = itemId;
return _item;
}
public T makeNewFromOther(string itemId, T other)
{
T _item = new T();
_item.id = itemId;
return _item;
}
}
public class DelegateHolder
{
public delegate T MakeWithID<T>(string id) where T: IItem, new();
public delegate T MakeWithIDAndOther<T>(string id, T other) where T: IItem, new();
}
public class Program
{
public static void Main()
{
var x = new TypedFactory<Item>();
BaseFactory<Item> factory = x;
Item someItem = factory.funcA("I am alive");
Console.WriteLine(someItem.id);
Console.WriteLine(factory.funcB("I am alive too", someItem).id);
}
}

Implementing a Generic Interface and a Non Generic Interface

I have two contracts (one Generic Interface and the other Non-Generic) as follows:
public interface IGenericContract<T> where T : class
{
IQueryable<T> GetAll();
}
public interface INonGenericContract
{
string GetFullName(Guid guid);
}
I have a class implementing both
public class MyClass<T> :
IGenericContract<T> where T : class, INonGenericContract
{
public IQueryable<T> GetAll()
{
...
}
public string GetFullName(Guid guid)
{
...
}
}
Everything is fine until this point when I compile it.
But now when I try using this class I run into this error
"error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'ConsoleApplication1.MyClass'. There is no implicit reference conversion from 'string' to 'ConsoleApplication1.INonGenericContract'."
class Program
{
static void Main(string[] args)
{
MyClass<string> myClass = new MyClass<string>(); //Error
}
}
If I do not implement the Non-generic contract it works fine. What could be wrong here ?
Thanks
In your code INonGenericContract is part of generic constraint, as it placed after where.
public class MyClass<T> :
IGenericContract<T> where T : class, INonGenericContract
You likely want that:
public class MyClass<T> :
IGenericContract<T>, INonGenericContract where T : class
you are very close, what you have to do is implement the non generic interface, not put a constrain.
public class MyClass<T> :
IGenericContract<T>, INonGenericContract where T : class
{
public IQueryable<T> GetAll()
{
return null;
}
public string GetFullName(Guid guid)
{
return null;
}
}
now you can do this
MyClass<string> myClass = new MyClass<string>();
According what you show
public class MyClass<T> : IGenericContract<T> where T : class, INonGenericContract
T must implement INonGenericContract and string doesn't implement it. In short, string is not a valid parameter for class MyClass
If what you're looking for is implementing IGenericContract<T> AND INonGenericContract you should have
public class MyClass<T> : INonGenericContract, IGenericContract<T>
there is no need to have where T : class since IGenericContract<T> already has that constraint.

Generics inheritance compile error

I'm getting a compile error when I try to compile this
The type 'WpfApplication2.CommandInstrumentTrade' cannot be used as type parameter 'T' in the generic type or method 'WpfApplication2.GenericWindowBase'. There is no implicit reference conversion from 'WpfApplication2.CommandInstrumentTrade' to 'WpfApplication2.GenericCommandBase'
public interface IBaseClass
{
int ID { get; set; }
}
public class BaseClass : IBaseClass
{
public int ID { get; set; }
}
public class DerivedClass : BaseClass
{
}
public class Command
{
}
public class GenericCommandBase<T> : Command where T : IBaseClass
{
}
public class DerivedGenericCommand : GenericCommandBase<DerivedClass>
{
}
public class GenericWindowBase<T> where T : GenericCommandBase<IBaseClass>
{
}
public class DerivedGenericWindow : GenericWindowBase<DerivedGenericCommand> // this line fails
{
}
The issue is that Generic<Derived> does not satisfy the condition where T : Generic<Base>. Even if Derived derives from Base, Generic<Derived> does not derive from Generic<Base>
There are many questions like that in StackOverflow.
Try reading those:
C# Generics Inheritance
generic inheritance in C#?
Inheritance doesn't compose with generics. You need to create some kind of converter from one to another. Maybe if you present some less abstract code we could help You

Categories

Resources