This question already has answers here:
In C#, what is the difference between public, private, protected, and having no access modifier?
(19 answers)
Closed 8 years ago.
I have a simple inheritance situation as follows:
I expected to be able to set the properties in Class2 from Class1 but this is not the case. Is there a way to set access to the properties in Class 2 so they act like protected variables?
public abstract class Class2
{
public DateTime Added { get; private set; }
public int ID { get; private set; }
}
public class Class1 : Class2
{
public string ImageFilename { get; set; }
public string LinkText { get; set; }
}
You need to set them as protected, not private. This lets you access it from derived classes, but not external classes.
public abstract class Class2
{
protected DateTime Added { get; set; }
protected int ID { get; set; }
}
public class Class1 : Class2
{
public string ImageFilename { get; set; }
public string LinkText { get; set; }
public Class1()
{
//You can set the variables from inside Class 1.
base.Added = DateTime.Now();
base.ID = 1;
}
}
If you want the properties to still be exposed externally, but as readonly, you can set the individual setters are protected instead:
public abstract class Class2
{
public DateTime Added { get; protected set; }
public int ID { get; protected set; }
}
Related
There is the following class:
public class A
{
[Required]
public string property { get; set; }
}
and it's used by another class like:
public class B
{
public A prop { get; set; }
public A prop2 { get; set; }
}
in my scenario, B.prop.property should be required while B.prop2.property should not be [Required].
Is there a way to override prop2.property attribute to be not required? and it also should affect the record recorded in the Database?
if not what is the most recommended practice to deal with such issue?
No. There is no way to achieve what you're talking about. You can do so via inheritance. For example:
public class C : A
{
public new string property { get; set; }
}
Then:
public class B
{
public A prop { get; set; }
public C prop2 { get; set; }
}
In other words, the property must literally be a type where that property is not required. You can't just disable an attribute on a class instance at a whim.
Starting off, I'm working with EF, since I'm building an MVC application on C#. I want different types of exams to have different types of questions. Here are my abstract classes:
public abstract class Exam
{
public int Id { get; set; }
public string Description { set; get; }
public abstract ICollection<Question> GetQuestions();
public abstract void SetQuestions(ICollection<Question> questions);
}
public abstract class Question
{
public int Id { get; set; }
public string Description { set; get; }
public abstract Exam getExam();
public abstract void setExam(Exam exam);
}
Notice that instead of the typical public virtual ICollection<Question> in the Exam class declaration, I created an abstract setter and getter. So is the case for the Exam property in the Question class.
Here are my concrete Exam classes:
[Table("SingleExam")]
public class SingleExam : Exam
{
public virtual ICollection<SingleQuestion> Questions { get; set; }
public override ICollection<Question> GetQuestions() { return Questions as ICollection<Question>; }
public override void SetQuestions(ICollection<Question> questions)
{
if (!(questions is ICollection<SingleQuestion>))
throw new ArgumentException("You must set single questions.");
Questions = questions as ICollection<SingleQuestion>;
}
}
[Table("MultipleExam")]
public class MultipleExam : Exam
{
public virtual ICollection<MultipleQuestion> Questions { get; set; }
public override ICollection<Question> GetQuestions() { return Questions as ICollection<Question>; }
public override void SetQuestions(ICollection<Question> questions)
{
if (!(questions is ICollection<MultipleQuestion>))
throw new ArgumentException("You must set multiple questions.");
Questions = questions as ICollection<MultipleQuestion>;
}
}
...And my concrete Question classes:
[Table("SingleQuestion")]
public class SingleQuestion : Question
{
public int ExamId { get; set; }
public virtual SingleExam Exam { get; set; }
public override Exam getExam() { return Exam; }
public override void setExam(Exam exam)
{
if (!(exam is SingleExam))
throw new ArgumentException("You must set a SingleExam");
Exam = exam as SingleExam;
}
}
[Table("MultipleQuestion")]
public class MultipleQuestion : Question
{
public int ExamId { get; set; }
public virtual MultipleExam Exam { get; set; }
public override Exam getExam() { return Exam; }
public override void setExam(Exam exam)
{
if (!(exam is MultipleExam))
throw new ArgumentException("You must set a MultipleExam");
Exam = exam as MultipleExam;
}
}
I did all this because a MultipleExam should only have MultipleQuestions, and a SingleExam should only have SingleQuestions, the same way that MultipleQuestion should have a MultipleExam and Single question should have a SingleExam.
Is there a better way to ensure that a subclass of a class 'A' contains or has a specific subclass of class 'B' (As is the case with my Exams and Questions), and having access to it through the abstract class without the abstract getters and setters?
As other have mentioned I think you are over complicating your problem.
However; your question is about type guarantees and I will try to answer that.
First the code:
public interface IExam<out T> where T:IQuestion {
int Id { get; set; }
string Description { set; get; }
IEnumerable<T> GetQuestions();
}
public interface IQuestion{
int Id { get; set; }
string Description { set; get; }
IExam<IQuestion> Exam { get; }
}
public class SingleQuestion:IQuestion {
public string Description { get; set; }
public int Id { get; set; }
IExam<IQuestion> IQuestion.Exam {
get { return Exam; }
}
public SingleExam Exam { get; set; }
}
public class SingleExam:IExam<SingleQuestion> {
public int Id { get; set; }
public string Description { get; set; }
private IEnumerable<SingleQuestion> _questions;
public IEnumerable<SingleQuestion> GetQuestions() {
return _questions;
}
public void SetQuestions(IEnumerable<SingleQuestion> questions) {
_questions = questions;
}
}
First of all we have replaced the abstract classes with interfaces.
This is required because we want to make IExam covariant on IQuestion and covariance can only be defined in an interface. This is also why we change to an IEnumerable for the collection.
Note we do not define the SetQuestions method in IExam in short this is because we can't. In long it is because that would make T contravarient as well as contravarient which would in turn lead to circumstances where type guarantees could not be made.
IQuestions is fairly straight forward no real changes here. You could, I suppose, leave it as an abstract type though.
Now the implementations:
In SingleQuestion we must explicitly implement Exam which expects an IExam then shadow it with a property that returns a SingleExam.
This allows us to return the most exact type of exam possible.
SingleQuestion sq = new SingleQuestion();
IQuestion q = sq; //Upcast
sq.Exam; //returns a SingleExam
q.Exam; //returns a IExam<IQuestion>
In SingleExam you can now set the questions and restrict it so that only SingleQuestions may be added.
As an aside it is now easier to see why SetQuestions cannot be defined in IExam. Consider the following:
SingleExam se = new SingleExam();
IExam<IQuestion> singleUpcast = se;
//What type of question can we set on singleUpcast?
All we know is that singleUpcast contains IQuestions but we can't just add IQuestions because singleUpcast is ultimately an instance of SingleExam which promised that only SingleQuestions could be set so it. In short it is not possible to know what types can be added to IExam without potentially breaking type guarantees
I created the following abstract class:
public abstract class AbstractClass
{
public abstract string Name { get; set; }
public abstract object Value { get; set; }
}
Now I want to derive two classes of the abstract class. I want to use an enum instead of the type object. My derived classes look like this:
First class:
public class InheritanceClass1:AbstractClass
{
public override string Name { get; set; }
public override FirstEnum Value { get; set; }
}
Second class:
public class InheritanceClass2 : AbstractClass
{
public override string Name { get; set; }
public override SecondEnum Value { get; set; }
}
I'm getting an error showed in my code, that the type of the property Value isn't object. I tryed to use the new-keyword instead of override like this:
In my abstract class:
public object Value { get; set; }
In my derived class:
public new FirstEnum Value { get; set; }
But if I create a List<AbstractClass> I have the problem that I can't use it for example for Linq because I would retrieve the "wrong" property. It is just hided, but still there, so I have to override the property.
So how do I have to change my abstract class and my derived classes, that I can use different types in my derived classes?
You can use abstract class like this:
public abstract class AbstractClass<T>
{
public abstract string Name { get; set; }
public abstract T Value { get; set; }
}
And derived class will change like this:
public class InheritanceClass1 : AbstractClass<FirstEnum>
{
public override string Name { get; set; }
public override FirstEnum Value { get; set; }
}
If you know that you will need only enums, you can add struct, IConvertible restriction to T:
public abstract class AbstractClass<T> where T : struct, IConvertible
{
public abstract string Name { get; set; }
public abstract T Value { get; set; }
}
Update based on comment:
Not the cleanest solution if you need List<AbstractClass>, but you can have additional class:
public abstract class AbstractClass
{
public abstract string Name { get; set; }
public abstract int GetValue ();
}
Which will then be inherited by AbstractClass<T>:
public abstract class AbstractClass<T> : AbstractClass where T : struct, IConvertible
{
public abstract T Value { get; set; }
}
And InheritancClass:
public class InheritanceClass1 : AbstractClass<FirstEnum>
{
public override string Name { get; set; }
public override FirstEnum Value { get; set; }
public override int GetValue () => (int)Value;
}
And then you can use it in a list:
var list = new List<AbstractClass> { new InheritanceClass1 (), new InheritanceClass2 () };
In this way you can use List<AbstractClass> with GetValue method. If you are using only enums you can always recast it to enum value. Ofcorse, you would not know exactly which enum it is, but you can add additional field for that.
I have the following two classes:
abstract class LogItem {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
class MyLogItem : LogItem
{
//No I want this to have to have the members from the abstract class above, as if it where an interface?
}
So in other words I am wanting a type if interface that can have definitions or variables which all classes that implement it have to have, but they could add more if they required ?
The above example builds, even if i dono add the members from the abstract class.
edit
Forget what I've said before. These are attributes, not methods. For them to be accessible on derived classes, you make them protected or public. The difference is that public members are visible to the world, while protected ones are visible to the class and subclasses.
Any class derived from your LogItem may have other variables.
abstract class LogItem {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
class MyLogItem : LogItem
{
//No I want this to have to have the members from the abstract class above, as if it where an interface?
private void TestMethod(){
String test = payload;
}
}
check out this post for more information
Your MyLogItem class can reference any of the above members directly. They are accessible
You may declare an interface with those
public interface MyInterface {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
and your class
public class MyLogItem : MyInterface
{
String _payload;
public String payload { get{ return _payload; } set {_payload=value;} }
...
}
The abstract keyword can also be applied to methods, as described here.
[DataContract]
public class UniqueNamedItem
{
[DataMember]
int Id { public get; protected set; }
[DataMember]
string Name { public get; protected set; }
}
[KnownType(typeof(UniqueNamedItem))]
[DataContract]
public class BasicNode : UniqueNamedItem
{
[DataMember]
SortedList<string, BasicNode> Children { public get; private set; }
public void addChild(BasicNode bn)
{
this.Children.Add(bn.Name, bn);
}
}
Can you tell me why inside my addChild function the call to bn.Name is not valid even though the UniqueNamedItem.Name property has a public get accessor?
The default accessibility for members of classes is private.
So Id and Name are private.
You need to add the correct access modifiers (I added public, you may have meant protected):
[DataContract]
public class UniqueNamedItem
{
[DataMember]
public int Id { public get; protected set; }
[DataMember]
public string Name { public get; protected set; }
}
One good reason to always declare the accessibility you want.
The UniqueNamedItem.Name property itself is private; you need to explicitly mark the property as public.
The modifiers on accessors can only restrict access further, not increase it.
You need to declare your properties as public (see below). The default is private.
[DataContract]
public class UniqueNamedItem
{
[DataMember]
public int Id { public get; protected set; }
[DataMember]
public string Name { public get; protected set; }
}
You need to make your properties public:
[DataContract]
public class UniqueNamedItem
{
[DataMember]
public int Id { public get; protected set; }
[DataMember]
public string Name { public get; protected set; }
}
Your properties are not explicitly marked as public, thus C# automatically considers them to be private.
So:
[DataContract]
public class UniqueNamedItem
{
[DataMember]
int Id { public get; protected set; }
[DataMember]
public string Name { public get; protected set; }
}
The default access is private, because if you make something public when it should really be private, it won't stop any correct code from working, and it could be that way for years before you realise (and it's also a breaking change to then fix it).
If on the other hand you make something private when it should be public, something will stop working immediately, you go on stackoverflow, a bunch of people say it's private, you fix it, and all is well.
Hence it's a sensible default.