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.
Related
Is there any way to auto generate a constructor which looks like this:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public User(int id, string name)
{
Id = 0;
Name = "";
}
}
Currently I am creating a constructor like that with the refactoring tool (CTRL + .):
public User(int id, string name)
{
Id = id;
Name = name;
}
and editing each line afterwards which is pretty cumbersome when you have 20 properties per class. Is there a better way to that?
(Maybe to define a code snippet, so that we can somehow read the class properties with reflection and define them as snippet parameters?)
If you have a class with 20 properties, why do you need a constructor with 20 parameters? Maybe have a sense, but I usually create constructors to initialize properties that are relevant, to simplify the code, not to set all properties.
For your class, you can set the default values when you define the property and all constructors will use this values as the default.
public class User
{
public int Id { get; set; } = 0;
public string Name { get; set; } = string.Empty;
// Here you can even omit the constructor
public User()
{
}
}
Another thing that maybe useful is define a constructor with X parameters and reuse this constructor in other constructors with less parameters:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public User()
: this(0, string.Empty)
{
}
public User(int id, string name)
{
Id = id;
Name = name;
}
}
You can replace this(0, string.Empty) for this(default, default) if you want use the default value of each type.
If you need object create with default value for properties. You can code like this:
public class User
{
public int Id { get; set; } = 0;
public string Name { get; set; } = "";
}
Purpose of quick action "generate constructor" make method contructor for assign value to fields or properties. Don't use it in the case of just assigning default values.
do you mean initialize properties? Initializing properties through the code reflection mechanism also requires one-by-one assignments. For private object properties, it is necessary to de-private encapsulation. The operation of initializing properties in c# is generally to initialize object properties or object initializers in the form of constructors. Thank you hope it helps you
class Program
{
static void Main(string[] args)
{
Student student = new Student()
{
age = 25,
name = "java",
sex = "female"
};
}
class Student
{
public int age { get; set; }
public string name { get; set; }
public string sex { get; set; }
public Student()
{
}
public Student(int age, string name,string sex)
{
this.age = age;
this.name = name;
this.sex = sex;
}
}
}
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 + ");
}
}
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 two functions that do the basically same thing on two different classes.... each class has different properties.
For example:
public class ClassA
{
public int ColorID {get;set;}
public string ColorDescription {get;set;}
}
public class ClassB
{
public int TypeID {get;set;}
public string TypeDescription {get;set;}
}
public void ExFunctionSaveA(ClassA aClass)
{
aClass.ColorID=1;
aClass.ColorDescription="My Color";
Save();
}
public void ExFunctionSaveB(ClassB bClass)
{
bClass.TypeID=2;
bClass.TypeDescription="My Type";
Save();
}
As you can see the classes and the functions have the same type structure, just the property names are different... but I feel like I am repeating code doing this
Is there a way to make ExFunctionA and ExFunctionB into one function, so that I could use this for all classes that have similar structure
I know I could do some sort of generic thing like
public void ExFunctionSave<T>() // T is either ClassA or ClassB
{
.
.
.
.
Save();
}
but how would I handle the properties of each
Rather than using a generic, why not use inheritance to solve this?
public class theBase
{
string ID;
string Description;
}
public class theColor : theBase
{
}
public class theType : theBase
{
}
public void ExFunctionSaveA(theBase base)
{
base.ID=1;
base.Description="My Color";
Save();
}
If you can alter the definitions of your classes, then the best approach would be to make them implement a common interface that contains the properties you want to access:
public interface IDescribable
{
int ID { get; set; }
string Description { get; set; }
}
public class ClassA
{
public int ID { get; set; }
public string Description { get; set; }
public int ColorID
{
get { return ID; }
set { ID = value; }
}
public string ColorDescription
{
get { return Description; }
set { Description = value; }
}
}
public class ClassB
{
public int ID { get; set; }
public string Description { get; set; }
public int TypeID
{
get { return ID; }
set { ID = value; }
}
public string TypeDescription
{
get { return Description; }
set { Description = value; }
}
}
public void ExFunctionSave(IDescribable d, int id, string desc)
{
d.ID = id;
d.Description = desc;
Save();
}
Nothing more you can do unless the the 2 classes implement the same interface which has the function. In your case, even the function signatures are different.
You could define an Interface with attributes id and description.
The clases that has this structure could implement that interface.
And your method receive as parameter the interface and execute the moethods ...
Take a look at Reflection.
Reflection will let your code receive a ClassA, and discover that it has a ColourID and a ColorDescription. Likewise, when you receive a ClassB, you can discover its TypeID and TypeDescription. It's cool.
I would probably recommend a common interface, at least for your example, but if you're trying to something more complex and more generic, Reflection is the way to go.
For C# properties, I can do this:
public class Employee{
public string Name { get; private set; }
public Employee(string name){
Name = name;
}
}
which means that the Name property can be set within the class Employee & can be read publicly.
But, if I want to restrict the set to only within the constructors of the Employee class, I need to do:
public class Employee{
public readonly string Name = String.Empty;
public Employee(string name){
Name = name;
}
}
But, for this case, I had to change the property to a field.
Is there any reason this is not possible/allowed in C#:
public class Employee{
public string Name { get; private readonly set; }
public Employee(string name){
Name = name;
}
}
IMO this will allow us to have properties which can be set only in the constructor & does not require us to change properties to fields...
Thanks!
Use
private readonly string name = Empty.String;
public string Name { get { return name; } }
What's wrong with:
public class Employee
{
private string nameField;
public string Name
{
get
{
return this.nameField;
}
}
public Employee(string name)
{
this.nameField = name;
}
readonly applies to variables and not to methods. set is converted into a method by the compiler, and therefore the readonly attribute makes no sense.
In order to accomplish what you want you need.
public class Employee
{
private readonly string _name;
public string Name
{
get
{
return _name;
}
}
public Employee(string name)
{
_name = name;
}
}
If you're concerned with only setting the properties within the constructor of the class that you're currently within, just make it a property with a private setter and don't set it in the class.. it's not like you don't have control over that situation.
$0.02
You can have
public class Employee{
public string Name { get; private set; }
public Employee(string name){
Name = name;
}
}
Which will make a readonly public property. If you think about it, having a private readonly setter on a public property doesn't really make sense because you're wanting the setter to be readonly which is a method, not a variable.
If you were to make the setter readonly, essentially what you're doing is denying any access whatsoever to setting the value of the property. This is why you need the backing field.