How can I define a static instance of an abstract class? - c#

I'm working with an abstract class in C# being inherited by multiple classes. One of the things I've been needing in my code is a static property such as "Unset", which would be a static instance of the class with it's main properties defined to an unset value. A generic example is as follows:
public abstract class Person
{
public string Name {get; set;}
public string PhoneNumber {get; set;}
public static readonly Person Unset = new Person() {
Name = "Unset Name"
PhoneNumber = "Unset Phone"
}
}
However I can't construct the "Unset" property because Person is an abstract class. I don't want to define the property for every class that derives from "Person". Is there a way to work around this?

You can't create an instance of an abstract class.
What you can do, however, is create a new child:
public class UnsetPerson : Person
{
public UnsetPerson() : base()
{
this.Name = "Unset Name";
this.PhoneNumber = "Unset Phone";
}
}
And then set the static property on your base class:
public abstract class Person
{
public string Name { get; set; }
public string PhoneNumber { get; set; }
public static readonly Person Unset = new UnsetPerson();
}

The documentation shows that the abstract keyword indicates that the thing being modified has a missing or incomplete implementation. As a result, it cannot be directly created, and can only be used through inheritance.
Since you don't (currently) have any abstract members in your abstract class, you could instead go with a virtual class, which allows you to provide a default implementation that can be optionally overwritten.
public virtual class Person
{
public virtual string Name { get; set; }
public virtual string PhoneNumber { get; set; }
public static readonly Person Unset = new Person() {
Name = "Unset Name",
PhoneNumber = "Unset Phone"
};
}
If you don't need/want to override any of the class members in an inheriting class, you don't need to make an abstract or virtual class. Any (non-sealed) class can be inherited.

I don't fully understand your requirements. Do you want to make sure that a freshly created instance of a derived class has those "unset" values? That could be done with a constructor in the abstract class:
protected Person()
{
Name = "Unset Name";
PhoneNumber = "Unset Phone";
}
Yes, an abstract class can have a constructor, even though you cannot instantiate it directly. The constructor of a base class is called before the constructor of a derived class, so that you can overwrite those "unset" values in the constructor of a derived class whenever it has appropriate parameters.

Related

Initializing a nested member with properties unknown in advance

There is an abstract class Subject which has 2 derived classes: Company and Person. Both have shared members like name or address as well as not shared properties unique to each. Let's say the Company has a property int employeesNumber, while person has a property string insuranceID. Now, since both Company and Person are supposed to work in the same pipeline (being stored in lists, seinding data to userforms etc), those "odd" properties are the cause of my problems. Here's what I tried to do:
first I make a base abstract class Subject which has the shared name and address properties as well as an interface IOtherProps for the odd properties. Even though the classes, implementing the interface share no properties by design, and therefore the interface is a blank, I used it so only few classes could be valid to implement it.
public abstract class subject
{
public string name { get; set; }
public string address { get; set; }
public IOtherProps otherprops;
}
public interface IOtherProps
{
}
Next, we have Company and Person derived classes, each implementing PropsCompany and PropsPerson classses respectively through IOtherProps to store the class specific data:
public class Company : Subject
{
public Company()
{
otherprops = new PropsCompany();
}
}
public class Person : Subject
{
public Person()
{
otherprops = new PropsPerson();
}
}
public class PropsCompany : IOtherProps
{
public int employeesNumber { get; set; }
}
public class PropsPerson : IOtherProps
{
public string insuranceID { get; set; }
}
Now let's try to initialize an object:
static void Main(string[] args)
{
Person person = new Person()
{
name = "John Smith", //ok
otherprops = { insuranceID = "12345" } // CS0117 C# \
//"IOtherProps" doesn't contain definition for "insuranceID".
};
}
C# won't let me initialize a nested class that only get initialized in the Person() constructor. The linter won't even give me a prompt on the members of otherprops and I might not remember which class contains which odd properties.
So I tried to override the otherprops in the Person class, got another error:
public class Person : Subject
{
public Person()
{
}
public override PropsPerson otherprops = new PropsPerson();// CS0106 C# The modifier
//'modifier' is not valid for this item
}
So, my question is: how do I initialize insuranceId in this example? And more general question: is my solution of handling the "odd" data like that is generally correct or am I missing something?
otherProps is defined on the subject base class as IOtherProps, which does not contain insuranceID.
Furthermore, you cannot override a field. If it was a property you could declare it virtual to solve CS0117, but you cannot override a property with a different type.
You need to declare subject as a generic type, and declare the field/property as that type:
public abstract class subject<TOtherProps> where TOtherProps : IOtherProps
{
public string name { get; set; }
public string address { get; set; }
public TOtherProps otherprops {get; set;} // or you could leave it as a field
}
Then Person can be declared like so:
public class Person : Subject<PropsPerson>
Now, the type of otherprops is statically known to be PropsPerson, which also implements IOtherProps.
Instead of the IOtherProps interface, I would just add the other properties unique to the Person and Company classes directly in those classes.
public abstract class Subject
{
public string Name { get; set; }
public string Address { get; set; }
}
public class Person : Subject
{
public Person()
{
public string InsuranceID { get; set; }
}
}
This is the more common implementation for multiple concrete implementations of an abstract class and easily allows you to do exactly what you want.
static void Main(string[] args)
{
Person person = new Person()
{
Name = "John Smith",
InsuranceID = "12345"
};
}
The only thing you lose the supposed protection of only a few classes being able to implement it but I'm not sure how effective that would be anyway.

How to access some properties (not all) of parent class in child class?

I have a class Person (Parent class) which contains some properties. Let's say 2 properties. I want to access 1 properties out of 2 properties in Student (child class) from Person class(Parent class).
Note: All properties are public which I need to use in other child class.
How will I achieve that using C#? (This applies to any object oriented programming languages)
Below is my sample code.
using System;
public class Person
{
public string name; //only want this property in all child classes
public float salary; //don't want to access this property in Student
}
public class Student: Person
{
public string subject;
}
public class Employee: Person
{
public int employeeId;
}
You shouldn't have salary as a field in Person unless all Persons have a salary,
this should instead go in the Employee class, or the highest class which uses salary
There is a conceptual problem in your code! The salary property is not general enough to be in the person class (not every person has a salary). You should not include this property in the Person class.
Using an interface would help only if:
you have multiple subclasses and some of them have salaries
you need to manage the subclasses that have salaries as a group without knowing the particular type of each one (e.g. polymorphism).
Hope that helps!
You can use an interface to achieve what you are aiming for. It doesn't stop the compiler from creating a Salary property for student object. But by using IStudent, you can restrict the access of the end user.
public class Person
{
public string Name { get; set; } //only want this property in all child classes
public float Salary { get; set; } //don't want to access this property in Student
}
interface IStudent
{
string Name { get; set; }
string Subject { get; set; }
}
public class Employee : Person
{
public int EmployeeId { get; set; }
}
public class Student : Person, IStudent
{
public string Subject { get; set; }
}
class Program
{
static void Main(string[] args)
{
IStudent s = new Student() { Name = "Student1", Subject = "Subject1" };
Console.WriteLine(s.Name);
}
}

C# Properties in interfaces & abstract classes

I was just coding a simple C# interface, and I put a property in it without thinking it through too far. For example:
public interface IMyInterface
{
string Name { get; set; }
object[][] Data { get; set;
}
I realized that I'm a little confused with properties when applied to interfaces and abstract base classes. In a normal class, this syntax would generate the accessor and mutator for a hidden string member that it generated behind the scenes.
Interfaces shouldn't be able to have data members. So, does this syntax do something different in that case?
What about for abstract classes? If I put this same syntax in the abstract base and the derived class, would both end up with a hidden member?
Interfaces shouldn't be able to have data members.
Those are properties, and those are allowed:
An interface contains only the signatures of methods, properties, events or indexers.
See also c# properties on Interface.
As for your second question:
If I put this same syntax in the abstract base and the derived class, would both end up with a hidden member?
Yes. You can prevent that by marking the property virtual on the base class and override on the derived class.
The property declaration in the interface is completely separate from the implementation. Thus you can implement it using automatic properties
private class MyImpl : IMyInterface
{
public string Name { get; set; }
public object[][] Data { get; set; }
}
or declare your own backing field
private class MyImplBacked : IMyInterface
{
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public object[][] Data { get; set; }
}
Same scenario in abstract classes
public abstract class MyAbstractClass
{
public abstract string Name { get; set; }
public abstract object[][] Data { get; set; }
}
private class MyImpl : MyAbstractClass
{
public override string Name { get; set; }
public override object[][] Data { get; set; }
}
private class MyImplBacked : MyAbstractClass
{
private string _name;
public override string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public override object[][] Data { get; set; }
}
Interfaces shouldn't be able to have data members. So, does this syntax do something different in that case?
Technically it's not a data member - it's a get/set method pair that has an underlying data member. There's no implementation.
What about for abstract classes? If I put this same syntax in the abstract base and the derived class, would both end up with a hidden member?
If the class is abstract and the property is virtual then yes, you will be overriding an auto-implemented property with another auto-implemented property (which is pointless).
If the class is abstract and the property is NOT virtual then you still have two implementations, but the base class is hiding the parent implementation rather than overriding it (which is still pointless if they're both auto-implemented).
If the property is abstract then the abstract class won't have an implementation. You'll have to implement the get/set in your concrete class (which could be auto-implemented bot doesn't have to be).

In C# is there no way to make a class define a field using an Interface or abstract class?

I would like to force a set of classes to define three fields (of type string).
In an abstract class, I get that fields cannot be abstract and in an interface, I get an error saying that an interface cannot contain a field.
Is there no way to do this or am I not understanding this correctly? I'd rather not use methods because for some weird reason, the parentheses annoy me.
You can use properties for that:
interface MyInterface {
string Prop1 { get; set; }
string Prop2 { get; set; }
string Prop3 { get; set; }
}
Interface or abstract members force derived classes to provide code.
Fields don't have code.
You should use a property, which can be used like a field, but has code.
You can use Properties instead of fields:
// works similarly for Interfaces too
abstract class MyAbstractClass { public virtual string MyProperty1 { get; set; } }
class MyConcreteClass : MyAbstractClass { }
Then you can access MyProperty1 from any instance derived from MyAbstractClass:
MyAbstractClass obj1 = new MyConcreteClass;
obj1.MyProperty1 = "abcd";
Like everyone else says, use properties instead of fields, but you can do something like I interpreted in the comments as follows for read-only members:
abstract public class Base
{
abstract public string Foo { get; }
abstract public string Bar { get; }
abstract public string Baz { get; }
}
public class Derived : Base
{
public override string Foo { get { return "foo"; } }
public override string Bar { get { return "bar"; } }
public override string Baz { get { return "baz"; } }
}
If you want the fields to be modifiable later, you'll have to either use automatic properties or declare concrete backing fields and getter/setter pairs for each property.

C# Inheritance: How to invoke the base class constructor when i call the derived class constructor

I am trying to figure out how to invoke a base class constructor when I call the derived class constructor.
I have a class called "AdditionalAttachment" which is inherited from System.Net.Mail.Attachment.I have added 2 more properties to my new class so that i can have all the properties of existing Attachment class with my new properties
public class AdditionalAttachment: Attachment
{
[DataMember]
public string AttachmentURL
{
set;
get;
}
[DataMember]
public string DisplayName
{
set;
get;
}
}
Earlier i used to create constructor like
//objMs is a MemoryStream object
Attachment objAttachment = new Attachment(objMs, "somename.pdf")
I am wondering how can I create the same kind of constructor to my class which will do the same thing as of the above constructor of the base class
This will pass your parameters into the base class's constructor:
public AdditionalAttachment(MemoryStream objMs, string displayName) : base(objMs, displayName)
{
// and you can do anything you want additionally
// here (the base class's constructor will have
// already done its work by the time you get here)
}
You can write a constructor that calls the class base constructor:
public AdditionalAttachment(MemoryStream objMs, string filename)
: base(objMs, filename)
{
}
Use this function:
public AdditionalAttachment(MemoryStream ms, string name, etc...)
: base(ms, name)
{
}
public class AdditionalAttachment: Attachment
{
public AdditionalAttachment(param1, param2) : base(param1, param2){}
[DataMember]
public string AttachmentURL
{
set;
get;
}
[DataMember]
public string DisplayName
{
set;
get;
}
}

Categories

Resources