I want to create a base class Student with a method changeName inside of it. I want studentclasses derived from the base class Student, such as collegestudent etc. I want to be able to change the names of the students.
I have this code:
public abstract class Student
{
public virtual void changeName(CollegeStudent s, string name)
{
s.firstName = name;
}
public abstract void outputDetails();
}
public class CollegeStudent : Student
{
public string firstName;
public string lastName;
public string major;
public double GPA;
public override void outputDetails()
{
Console.WriteLine("Student " + firstName + ");
}
}
I want to know if its possible to change the public virtual void changeName parameters to a generic parameter that accepts any derived class from Student.
Is this possible in c#?
(Something like this: public virtual void changeName(Anyderivedclass s, string name)
If you changed your design a little, things would become much easier. It seems like you're coming from a Java background, so lets see how C# can help improve your code.
First, Take the FirstName/LastName fields and move them to the base class, as any student registering must supply these anyway. Second, C# has a feature called Properties (specifically here we can use Auto-Implemented Properties, since we don't need validation), which is basically syntactic sugar for get/set methods. You can re-create you student class to look like this:
public abstract class Student
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
This will allow any instance of a derive class to change the firstname and lastname properties, without adding any extra methods:
void Main()
{
var student = new CollegeStudent();
student.FirstName = "Yuval";
}
Generally speaking, any instance method on the object you're creating shouldn't be accepting it's own type in order to mutate itself.
But changeName() is an instance method of your abstract Student. Why are you passing in an instance of one of it's derivatives as one of it's parameters?
Why do you need generics? It should be as simple as...
public abstract class Student
{
public abstract void changeName(string newName);
public abstract void outputDetails();
}
public class CollegeStudent : Student
{
public string firstName;
public string lastName;
public string major;
public double GPA;
public override void changeName(string newName)
{
firstName = newName;
}
public override void outputDetails()
{
Console.WriteLine("Student " + firstName + ");
}
}
And in fact (as pointed out) the presence of changeName() in the base class suggests that the name properties belong to the base class, so it should be as follows...
public abstract class Student
{
public string firstName;
public string lastName;
public virtual void changeName(string newName)
{
firstName = newName;
}
public abstract void outputDetails();
}
public class CollegeStudent : Student
{
public string major;
public double GPA;
public override void outputDetails()
{
Console.WriteLine("Student " + firstName + ");
}
}
Related
I have an Animal base class and every subclass needs a static string ID for identification purposes.
So I might have:
public class Dog : Animal {
public static readonly string ID = "dog";
}
I do this because I frequently need to use Dog.ID throughout my app - in places where I don't yet have an instance.
However, I also need to access this when I have an instance, but I only want to put something like GetId() in the base class:
public class Animal {
public string GetId() {
return ID;
}
}
The problem is, Animal would not have access to the static ID field in the children.
Is there a way to do this that I've overlooked?
What about an abstract method?
public class Dog : Animal
{
public static readonly string ID = "dog";
public override string GetId()
{
return ID;
}
}
public abstract class Animal
{
public abstract string GetId();
}
or virtual
public class Animal
{
public virtual string GetId()
{
return null;
}
}
Ugly... But you could use reflection:
FieldInfo id = GetType().GetField("ID", BindingFlags.Public | BindingFlags.Static);
return id.GetValue(null);
If this is a static, set-once identifier, it seems like you should use an attribute instead of a static field or property:
public class AnimalIdAttribute : Attribute
{
public AnimalIdAttribute(string id)
{
Id = id;
}
public string Id { get; }
}
public class Animal
{
public string Id => this.GetCustomAttribute<AnimalIdAttribute>(true)?.Id;
}
[AnimalId("dog")]
public class Dog : Animal
{
}
Also, if any animal should provide an Id, your Animal class should be an abstract class which should also define an abstract Id property:
public abstract class Animal
{
// Now you can access Id property implementation
// from Animal
public abstract string Id { get; }
}
public class Dog : Animal
{
public override string Id { get; } = "dog";
}
Or, you can do something like this:
public class Animal
{
public static string Id;
public virtual string GetId()
{
return Id;
}
}
public class Dog : Animal
{
public new static readonly string Id = "dog";
public override string GetId()
{
return Id;
}
}
This gives you ability to call Id from Class or an instance.
Implement explicit interface like this
public class Animal : IType
{
private static string _ID = "Animal";
string IType.ID
{
get
{
return getID();
}
}
public virtual string getID()
{
return _ID;
}
}
public class Dog : Animal, IType
{
public static readonly string _dogID = "dog";
string IType.ID
{
get
{
return _dogID;
}
}
public override string getID()
{
return _dogID;
}
}
....
// usage
Animal a = new Animal();
Animal d = new Dog();
Console.WriteLine(a.getID());
Console.WriteLine(d.getID());
If you agree to an assumption that ID equals to the type name, you can use this approach. It lets you define and inherit ID property in the base class.
Though I agree this might look quite strange at first sight.
public class Animal<T> where T : Animal<T>
{
public static readonly string ID = typeof(T).Name;
}
public class Dog : Animal<Dog>
{
}
public class Cat : Animal<Cat>
{
}
Expression Cat.ID will return Cat, and Dog.ID will return Dog.
Can we create a subclass of a base class, like creating a view of a table in SQL, in C#?
Example of desired behaviour:
public class EmployeeSpecificUsage : Employee
{
public string firstName;
public string field1;
public int age;
public string Name; //Error! Not implemented in main class
}
public abstract class Employee
{
public string firstName;
public string lastname;
public int age;
public string workTitle;
public string field1;
public string field2;
public string field3;
}
Objectives:
Reduce the number of field members visible.
Forbid adding new fields, respecting the original model.
Your understanding of subclassing is incorrect. Subclassing is a way of extending the base class, not taking away from it. Whatever a base class has, all subclasses would have it as well.
This is different from views in SQL, which can both take away columns and also add computed columns.
Although inheritance does not allow you to reduce the number of visible members, you can do it with composition. Wrap Employee in a RestrictedEmployee, and expose only the members that you want others to see:
public class EmployeeSpecificUsage {
private readonly Employee wrapped;
public EmployeeSpecificUsage(Employee e) {
wrapped = e;
}
public string firstName => wrapped.firstName;
public string field1 => wrapped.field1;
// Two fields above use C# 6 syntax. If it is not available,
// use syntax below:
public int age {
get {
return wrapped.age;
}
}
}
As far as prohibiting the addition of new fields goes, you cannot do that with either inheritance or composition: if you are allowed to subclass at all (i.e. the base class is not sealed) you would be able to add new members. Composition is a lot weaker than inheritance, so you could add new fields even to sealed classes by wrapping them.
An interface gives you access to an aspect of a class (as opposed to a derived class that actually extends the base class).
Have a look at this:
public class Employee : IEmployeeSpecificUsage
{
public string firstName { get; }
public string lastname { get; }
public int age { get; }
public string workTitle { get; }
public string field1 { get; }
public string field2 { get; }
public string field3 { get; }
}
public interface IEmployeeSpecificUsage
{
public string firstName { get; }
public string field1 { get; }
public int age { get; }
}
If you reference to an Employee instance by the IEmployeeSpecificUsage interface, you will only "see" what's in the interface.
You cannot add new interfaces without changing the "base class", though, as it has to declare that it implements those interfaces.
Interfaces can be used as views.
public interface IView
{
string FirstName { get; }
int Age { get; }
string Name { get; }
}
public class Employee: IView
{
// make fields private if possible
private string firstName;
private string lastname;
private int age;
private string workTitle;
private string field1;
private string field2;
private string field3;
// implements IView.FirstName as an auto property
public string FirstName { get; set; }
// implements IView.Age: returns the private age field
public int Age { get { return age;} }
// explicit implementation of IView.Name: visible only as IView
string IView.Name { get { return lastName + ", " + firstName; } }
}
And then:
Employee employee1 = new Employee(); // FirstName and Age are visible on employee1
IView employee2 = new Employee(); // Name is visible, too
If you want to provide a readonly access to an inner field of a class check out public Properties with getter. Make you field members protected. In such a way you will have an ability to implement custom logic for Name property composing it from firstname and lastname field.
public class EmployeeSpecificUsage : Employee
{
public string FirstName { get { return firstName; }};
public string FullName { get { return string.Format("{0} {1}", firstName, lastName); }};
}
public class Employee
{
protected string firstName;
protected string lastname;
protected int age;
protected string workTitle;
protected string field1;
protected string field2;
protected string field3;
}
An option would be to create properties in the base class with protected setters and public getters.
Im learning c# online, and I just finished an exercise, were I should create a class called "People" and create 5 variables that can make the peoples uniqe:
public string name;
public int age;
public double heigth;
public double weigth;
public string nationality;
public int shoeSize;
I also created a class called "Bank" and declaired 4 members:
int accountNumber;
string firstName;
string lastName;
string bankName;
then, I got the question: "If you think that the bank class is associated with one person (People class) how would you use the class "People" in the class for "Bank" ?
Now I clearly didnĀ“t understand what was being ment.. Any ideas`?
Edit: when do I need the constructor method?
That's not a constructor, that's trying to teach you that you can have classes you created as properties inside another class you create.
In their example, one person is per bank, so you could have the People class as a property called Person to signify who the account belongs to. You can do this by adding the following to your Bank class:
public People person { get; set; }
In terms of a constructor, you'd need one if you wanted to set some default properties. Consider this constructor for Bank:
public Bank()
{
accountNumber = 1;
firstName = "Default";
lastName = "Default";
bankName = "Default";
person = new People();
}
See that last line that creates person? If you removed that, but then tried to do this.person.name you'd get a NullReferenceException. That's because by default your person would have the value of null.
It could be as simple as:
public class People // I would call it person though, as People is plural
{
public int age;
public double heigth;
public double weigth;
public string nationality;
public int shoeSize;
}
public class Bank // I would call it BankAccount though
{
int accountNumber;
string firstName;
string lastName;
string bankName;
// The answer to the question:
People owner; // <-- Here the bank account has a reference to the People class,
// you provided in the constructor
// And if you need the constructor
public Bank(People owner, int accountNumber)// <-- This is the constructor
{
this.accountNumber = accountNumber;
this.owner = owner;
} // <-- The constructor ends here.
}
How about
public class Person
{
//A property for Name
//A property for Address
}
In another class a property for collection of Persons
public List<Person> People { get; set; }
Thats the way I would go:
public class Person
{
public int Age { get; set; } // I would use properties and public properties are
// starting with a great letter
public double Heigth { get; set; }
public double Weigth { get; set; }
public string Nationality { get; set; }
public int ShoeSize { get; set; }
}
public class BankAccount
{
private Person _person; // private field for the person object
public int AccountNumber { get; private set; } // public propertie for the account
// number with a private setter
// because normally you want to read
// that from the outside but not set
// from the outside
public string FirstName
{
get { return _person.FirstName; }
}
public string LastName;
{
get { return _person.LastName; }
}
public string BankName { get; set; }
public Bank(Person person, int accountNumber)
{
AccountNumber = accountNumber;
_person = person;
}
}
Please allways write down the access parameters from properties, methods etc.
I have a abstract class 'Building':
public abstract class Building {
abstract public int ID {get;}
abstract public string name {get;}
}
the class (for example) Headquarter : Building has the Variables for these getter and setter methods. The Problem is I have to write in every Subclass
private int _ID = 1;
public int ID {
get {return _ID;}
}
Is there a way to create for example one getter setter method like ahead, in the abstract class and save the code, so that I only have to set the variables?
Thanks for helping.
Instead of making the properties abstract, you could make the setter protected, and/or allow them to be set in the constructor:
public abstract class Building
{
// Optional constructor
protected Building(int id, string name)
{
this.ID = id;
this.Name = name;
}
public int ID { get; protected set; }
public string Name { get; protected set; }
}
This moves the implementation into the base class, but still only allows the subclasses to set those values.
You can try adding a protected setter in base class and set the value in ctor of derived classes:
public class Building
{
public int Id{get;protected set;}
and in derived class:
public class Headquarter: Building
{
public Headquarter()
{
Id = 1;
}
}
Assuming I have:
public abstract class A {
public abstract string Name { get; }
}
I want to use the "shortcut" for creating properties in the child class:
public string Name { get; set; }
Instead of:
private string _Name;
public string Name {
get{ return _Name; }
set{ _Name=Name; }
}
But this cause compilation error since I have set; there
public class B {
public override Name{get; set;}
}
How can I override only get;?
Just implement the getter:
public override string Name
{
get
{
return this.name;
}
}
private string name;
The shorthand for a simple get + set property is great if you want a simple get + set property, but if you want something more complicated (such as a property with just a getter) you need to implement it yourself.
Short answer: there is no shorthand way
public class B {
private string iName;
public override string Name{get{ return iName;}}
}
on a side note:
You could make your base class an interface and then override in the implementing class:
public interface A {
string Name { get; }
}
public class B : A {
public string Name {get;set;}
}