C# Cannot access child public method from abstract parent class object - c#

I'm learning OOAD and trying to implement class relationship with inheritance but there is an issue here is the code
Parent Class
namespace ConsoleApplication1
{
abstract class Classification
{
public abstract string type();
}
}
1st Child Class
namespace ConsoleApplication1
{
class FullTime : Classification
{
bool inCampus;
string roomDetail;
float rent;
public FullTime(string studentRoomDetail, float studentRent)
{
this.inCampus = true;
this.roomDetail = studentRoomDetail;
this.rent = studentRent;
}
public FullTime()
{
this.inCampus = false;
}
public string printAccommodationDescription()
{
if (!this.inCampus)
{
return "Not in campus";
}
else
{
return "Room: " + this.roomDetail + " Rent: " + this.rent.ToString();
}
}
public override string type()
{
return "fulltime";
}
}
}
2nd Child Class
namespace ConsoleApplication1
{
class PartTime : Classification
{
bool onJob;
string jobTitle;
float salary;
public PartTime(string studentJobTitle, float studentSalary)
{
this.onJob = true;
this.jobTitle = studentJobTitle;
this.salary = studentSalary;
}
public PartTime()
{
this.onJob = false;
}
public string printJobDescription()
{
if (!this.onJob)
{
return "Not on job";
}
else
{
return "JobTitle: " + this.jobTitle + " Salary: " + this.salary.ToString();
}
}
public override string type()
{
return "parttime";
}
}
}
Now in Program.cs when I tried to access method printJobDescription from PartTime class
Classification classification = new PartTime("Software Engineer", 10000);
classification.printJobDescription();
it says
Error CS1061 'Classification' does not contain a definition for 'printAccommodationDescription' and no extension method 'printAccommodationDescription' accepting a first argument of type 'Classification' could be found (are you missing a using directive or an assembly reference?)
How can I solve this issue?
UPDATE
I need the ability to let object change its class at runtime, so I have to create the object of type Classification and use either method that is not implemented in other class

You can only use the functions declared in the class you use.
abstract class Classification
{
public abstract string type();
}
class PartTime : Classification
{
public override string type() {...}
public Job1() {...}
}
class FullTime : Classification
{
public override string type() {...}
public Job2() {...}
}
A object of type Classification can only use the type()
A object of the type PartTime can use type and Job1()
A object of the type FullTime can use type and Job2()
If you have an object like this:
Classification classification = new PartTime();
and you don´t know which special type, you have to cast this object to use other methods:
if (classification is PartTime)
{
((PartTime)classification).Job1();
}
else if (classification is FullTime)
{
((FullTime)classification).Job2();
}
Hope this helps.

When casting you're object into another object type, that called Polymorphism. This translate that you can only use the methods and properties that exposed to the destination object type, which is Classification which doesn't know your method.
Simple example i made:
using System;
namespace Program
{
public class Program
{
public static void Main()
{
Dog rex = new Dog();
Animal rexAsAnimal = rex;
// Can access 'MakeSound' due the fact it declared at Dog (Inherited by Animal)
Console.WriteLine(rex.MakeSound()); // Output: Bark
// Compilation error: rexAsAnimal is defined as 'Animal' which doesn't have the 'Bark' method.
//Console.WriteLine(rexAsAnimal.Bark()); // Output when uncomment: Compilation error.
// Explicitly telling the compiler to cast the object into "Dog"
Console.WriteLine(((Dog)rexAsAnimal).Bark()); // Output: Bark
}
}
public abstract class Animal
{
public abstract string MakeSound();
}
public class Dog : Animal
{
public override string MakeSound() { return Bark(); }
public string Bark()
{
return "Bark";
}
}
}

Related

C# Problems using Inheritance - My first time

I'm having a few issues while trying use Inheritance. I create a class named vehicle with some properties, and the another one named car which inherits the properties from vehicle, them when I run the code below, the C# compiler returns the following error:
Program.cs (38,13): error CS0246: The namespace name or type 'car' could not be found. Need a policy using or an assembly reference?
Here's the code:
using System;
class vehicle
{
public int MaxSpeed;
public bool turnOn;
public int wheels;
public void car_on()
{
turnOn = true;
}
public void car_off()
{
turnOn = false;
}
class car : vehicle
{
public string name;
public string color;
public car(string name, string color)
{
this.name = name;
this.color = color;
MaxSpeed = 220;
wheels = 4;
turnOn();
}
}
}
namespace Aula_28_herança
{
class Program
{
static void Main(string[] args)
{
car c1= new car("ferrari","red");
Console.WriteLine("Nome................:{0}", c1.name);
Console.WriteLine("Cor.................:{0}", c1.color;
Console.WriteLine("Velociade Máxima....:{0}", c1.MaxSpeed);
Console.WriteLine("Quantiadade de Rodas:{0}", c1.wheels);
Console.WriteLine("Status..............:{0}", c1.turnOn);
}
}
}
You need to make your carro type public:
class veiculo{
....
public class carro : veiculo{
...
}
}
Ad use veiculo.carro for type:
veiculo.carro c1= new veiculo.carro("ferrari","vermelha");
See the docs on Nested Types:
Regardless of whether the outer type is a class, interface, or struct, nested types default to private; they are accessible only from their containing type.

How to get correct extension method for a generic class method?

I came across this recently while writing the code. Is there a way we can write a code in base class so it identifies the correct extension method based on the type?
namespace GenericsInheritance
{
public class Animal { }
public class Dinasaur : Animal { }
public class Dragon : Animal { }
public abstract class Zoo<T> where T : Animal
{
public virtual string IdentifyYourSelf(T record)
{
//Calling extension method
string name = record.IdentifyYourSelf();
return name;
}
}
public class DinasaurZoo : Zoo<Dinasaur>
{
//I could use this, just wanted to try if base class method does identify the correct extension method for the type.
//public override string IdentifyYourSelf(Dinasaur record)
//{
// return record.IdentifyYourSelf();
//}
}
public class DragonZoo : Zoo<Dragon> { }
public class AnimalZoo : Zoo<Animal> { }
//Extensions methods class.
public static class LieDetector
{
public static string IdentifyYourSelf(this Animal record) { return "Animal"; }
public static string IdentifyYourSelf(this Dinasaur record) { return "Dinasaur"; }
public static string IdentifyYourSelf(this Dragon dog) { return "Dragon"; }
//It works if I use this.
//public static string IdentifyYourSelf<T>(this T record) where T : Animal
//{
// if (record is Dinasaur) { var dinasaur = record as Dinasaur; return IdentifyYourSelf(dinasaur); }
// else if (record is Dragon) { var dragon = record as Dragon; return IdentifyYourSelf(dragon); }
// else return "I do not exist";
//}
}
public class FbiInterrogation
{
public static void Main(string[] args)
{
var animal = new Animal();
var dinasaur = new Dinasaur();
var dragon = new Dragon();
var dinasaurZoo = new DinasaurZoo();
var dragonZoo = new DragonZoo();
var animalZoo = new AnimalZoo();
string name = dinasaurZoo.IdentifyYourSelf(dinasaur); //Prints Animal expecting Dinasaur
name = dragonZoo.IdentifyYourSelf(dragon); //Prints Animal expecting Dragon
name = animalZoo.IdentifyYourSelf(animal); //Prints Animal
Console.ReadKey();
}
}
}
Extension methods are resolved according to the static type of the variable on which they're called, not the run-time type. So the answer to your question is "no" -- you have to do it via an override in the derived class, or by cumbersome type checking, as you indicate in your question.
This could actually be achieved using reflection, though I'm not sure if it's the best idea to do so:
public abstract class Zoo<T> where T : Animal
{
public virtual string IdentifyYourSelf(T record)
{
return typeof(LieDetector).GetMethod("IdentifyYourSelf", new[] {typeof(T)}, null).Invoke(record, new object[] {record}) as string;
}
}

How to get type of a derived class from another derived class

I have the (pseudo) code:
public class GlobalClass
{
public GlobalClass()
{
var x = this.GetType().Name // Returns "Channels"
// WHAT TO DO HERE?
}
}
public class BaseClass
{
public string Title { get; set; }
}
And using this code:
public class Channels : GlobalClass
{
public Channels()
{
}
public class Channel : BaseClass
{
}
}
Where the comment is (// WHAT TO DO HERE?), I want to get the runtime type of BaseClass,
where in my sample code should return Channel.
I am open to different approaches, but only if it's accompanied with an explanation why I should change the code.
I think you need a generic class here, something like:
public class GlobalClass<T> where T : BaseClass
{
public GlobalClass()
{
var theType = typeof(T); //you got it
}
}
public class BaseClass
{
public string Title { get; set; }
}
public class Channel : BaseClass { }
public class Channels : GlobalClass<Channel> { }
You can use reflection like this:
using System.Reflection;
...
public class GlobalClass
{
public GlobalClass()
{
Type[] types = Assembly.GetExecutingAssembly ().GetTypes ();
foreach ( Type t in types )
{
if ( t.BaseType == typeof ( BaseClass ) )
{
Console.WriteLine ( "I found a class " + t.Name + " that subclass BaseClass" );
}
}
}
}
See also Stack Overflow question List of classes in an assembly.
is operator is just for that purpose.
getType() method with class Type can also be used.
class Example
{
static void ShowTypeInfo (object o)
{
Console.WriteLine ("type name = {0},
full type name = {1}", o.GetType(),
o.GetType().FullName );
}
public static void Main()
{
long longType = 99;
Example example= new Example();
ShowTypeInfo (example);
ShowTypeInfo (longType);
}
}
To get the runtime type of anything, you first need an object instance to get the type from. So with your given structure, that's not possible.
There are two possible approaches:
Add a BaseClass parameter to the constructor of your GlobalClass:
public class GlobalClass
{
public GlobalClass(BaseClass data)
{
var dataType = data == null ? null : data.GetType();
// do something with the type
}
}
public class Channels : GlobalClass
{
public Channels(Channel data) : base(data)
{
}
public class Channel : BaseClass
{
}
}
Pass the type to the constructor directly:
public class GlobalClass
{
public GlobalClass(Type actualType)
{
Debug.Assert(typeof(BaseClass).IsAssignableFrom(actualType));
}
}
public class Channels : GlobalClass
{
public Channels() : base(typeof(Channel))
{
}
public class Channel : BaseClass
{
}
}
If the structure for some reason doesn't allow generics here (as Danny Chen suggested), I'd personally prefer the second approach, since that doesn't need an actual instance.

Call constant property on class like static?

I got an abstract base class
public class Base
{
public abstract String Info { get; }
}
and some children.
public class A : Base
{
public override String Info { get { return "A does ..."; } }
}
public class B : Base
{
public override String Info { get { return "B does ..."; } }
}
This is mere a constant but I want to make sure using Base that all classes implement it.
Now I sometimes do not have an object instance but want to access A.Info - this is not possible due it is a instance property.
Is there another way than implementing the same property on instance AND on static level? That would be feel like a duplicate violating DRY programming style.
NEW EDIT: I now see this two solutions:
public class Base
{
public abstract String ClassInfo { get; }
}
public class A : Base
{
public override String ClassInfo { get { return Info; } }
public static String Info { get { return "A does ..."; } }
}
public class B : Base
{
public override String ClassInfo { get { return Info; } }
public static String Info { get { return "In B we do ..."; } }
}
With this I can do with any object of type Base something like object.ClassInfo but also use the value in my factory hardcoded like if(A.Info) return new A(). But I have to implement two properties for the same information in every class.
On the other hand:
public class Base
{
public abstract String ClassInfo { get; }
public static String GetClassInfo<T>() where T : BaseControl, new()
{
T obj = new T();
return obj.ClassInfo;
}
}
public class A : Base
{
public override String ClassInfo { get { return "text A"; } }
}
public class B : Base
{
public override String ClassInfo { get { return "text B"; } }
}
Due to the abstract Base it is made sure that ClassInfo is always implemented. Calls with obj.ClassInfo and Base.GetClassInfo<A>() are okay. But with this every child of Base must have a default constructor without arguments and we loose performance with the unneccessary created instance.
Is there any other idea? Which one would you prefer and why?
If you need specific return results of your static properties, you're better of either
a) Instance properties
2) Attributes
In the example you've already given, you've got an instance of Base, which means you can just make the instance property virtual:
public class Base
{
public virtual string Info { get { return "From Base"; } }
}
public class A : Base
{
public override string Info { get { return "From A"; } }
}
If you wanted to go the attribute route, you define it as such:
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public class InfoAttribute : Attribute
{
public InfoAttribute(string info) { this.Info = info; }
public string Info { get; private set; }
}
[InfoAttribute(Info = "From Base")]
public class Base
{
public string GetInfo()
{
var attr = GetType()
.GetCustomAttributes(typeof(InfoAttribute), true)
.FirstOrDefault();
return (attr == null) ? null : attr.Info;
}
}
[InfoAttribute(Info = "From A")]
public class A : Base { }
If you wanted to call it as a static function call, you could make this change:
public static string GetInfo(Base instance)
{
var attr = instance.GetType()
.GetCustomAttributes(typeof(InfoAttribute), true)
.FirstOrDefault();
return (attr == null) ? null : attr.Info;
}
And then call it as: Base.GetInfo(instance);. All in all, not very elegant!
This is not possible.
static members cannot be virtual or abstract.
You should make an abstract instance property.
Statics can't be overridden. If you truly want to do something like that, you'd want an instance property that is virtual in the base that gets overridden in the subclasses.
Does it compiled? I don't think so. Static cannot be marked as override, virtual or abstract.

Override Property with different compatible Type

I need a base class with a property where I can derive classes with the same property but different (compatible) types. The base Class can be abstract.
public class Base
{
public virtual object prop { get; set; }
}
public class StrBase : Base
{
public override string prop { get; set; } // compiler error
}
public class UseIt
{
public void use()
{
List<Base> l = new List<Base>();
//...
}
}
I tried it with Generics but that gives me a problem when using the class, because I want to store differently typed base classes in the List.
public class BaseG<T>
{
public T prop { get; set; }
}
public class UseIt
{
public void use()
{
List<BaseG> l = new List<BaseG>(); // requires type argument
//...
}
}
Here's an alternative approach to proposed solution:
public abstract class Base
{
public abstract void Use();
public abstract object GetProp();
}
public abstract class GenericBase<T> : Base
{
public T Prop { get; set; }
public override object GetProp()
{
return Prop;
}
}
public class StrBase : GenericBase<string>
{
public override void Use()
{
Console.WriteLine("Using string: {0}", Prop);
}
}
public class IntBase : GenericBase<int>
{
public override void Use()
{
Console.WriteLine("Using int: {0}", Prop);
}
}
Basically I've added a generic class in the middle that stores your properly-typed property. this will work assuming that you never need to access Prop from the code that iterates the members of the List<Base>. (You could always add an abstract method to Base called GetProp that casts the generic to an object if that's required.)
Sample usage:
class Program
{
static void Main(string[] args)
{
List<Base> l = new List<Base>();
l.Add(new StrBase {Prop = "foo"});
l.Add(new IntBase {Prop = 42});
Console.WriteLine("Using each item");
foreach (var o in l)
{
o.Use();
}
Console.WriteLine("Done");
Console.ReadKey();
}
}
Edit: Added the GetProp() method to illustrate how the property can be directly accessed from the base class.
You can't override the type of a property. Take a look at the following code:
StrBase s = new StrBase();
Base b = s;
This is completely valid code. But what happens when you try to do this?
b.prop = 5;
The integer can be converted to object, because everything is derived from object. But since b is actually a StrBase instance, it would have to convert the integer to a string somehow, which it can't. So that is why you aren't allowed to override the type.
The same principle applies to generics:
List<BaseG<object>> l = new List<BaseG<object>>();
BaseG<string> s = new BaseG<string>();
// The compiler will not allow this.
l.add(s);
// Here's the same problem, convert integer to string?
BaseG<object> o = l[0];
o.prop = 5;
This is because generic types in C# 2.0 are invariant. C# 4.0 does allow this type of conversions, called covariance and contravariance.
Solutions
An option is to cast the object back to string when you need it. You could add type validation in the subclass:
public class StrBase : Base
{
private string propValue;
public override object prop {
get
{
return this.propValue;
}
set
{
if (value is string)
{
this.propValue = (string)value;
}
}
}
}
You could also expose a type-safe property in the subclass:
public class StrBase : Base
{
public string strProp {
get
{
return (string)this.prop;
}
set
{
this.prop = value;
}
}
}
This is possible since C# 9.0
Beginning with C# 9.0, override methods support covariant return types.
(see Microsoft docs)
public class First
{
private int someV;
public virtual object SomeV { get => someV; set => someV = (int)value; }
public First() { }
}
public class Two : First
{
private string someV;
public override object SomeV { get => someV; set => someV = value.ToString(); }
public Two() { }
}
and use of those:
First firstClass = new First();
firstClass.SomeV = 1;
Two twoClass = new Two();
twoClass.SomeV = "abcd";

Categories