Struggling a bit with inheritance here. I have common properties to use in two derived classes, so I made a base class LogBaseViewModel. I don't ever want this base class to be used except to be inherited by derived classes, so I made it protected (also tried private).
I found this bit, and maybe I'm mis-interpreting, but thought if I wrapped all 3 of these classes within one, they'd no longer be "outside" and hence this would be allowed.
From section 3.5.3 of the C# 5 specification:
When a protected instance member is accessed outside the program text
of the class in which it is declared, and when a protected internal
instance member is accessed outside the program text of the program in
which it is declared, the access must take place within a class
declaration that derives from the class in which it is declared.
Furthermore, the access is required to take place through an instance
of that derived class type or a class type constructed from it.
However, no joy, I get the error: Error CS0060 Inconsistent accessibility: base class 'LogViewModels.LogBaseViewModel' is less accessible than class 'LogViewModels.LogSearchViewModel'.
public class LogViewModels
{
protected class LogBaseViewModel
{
public int Id { get; set; }
public string Level { get; set; }
public string Message { get; set; }
public string Exception { get; set; }
}
public class LogSearchViewModel : LogBaseViewModel
{
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
}
public class LogViewModel : LogBaseViewModel
{
public System.DateTime Date { get; set; }
}
}
Applying the protected modifier on LogBaseViewModel would make it accessible only inside LogViewModels, and in subclasses of LogViewModels, not subclasses of LogBaseViewModel.
From here:
A protected member is accessible within its class and by derived class instances.
The "protected member" is the class LogBaseViewModel. "Its class" refers to the enclosing class LogViewModels.
By making LogBaseViewModel protected, you are telling the compiler that you don't want any external class to know about the insides of LogBaseViewModel. But then you said public class LogSearchViewModel : LogBaseViewModel. This allows people to access the insides of LogBaseViewModel through LogSearchViewModel! The compiler sees that this will make the protected modifier on LogBaseViewModel meaningless, so it gives you an error.
You said:
I don't ever want this base class to be used except to be inherited by derived classes.
Which is the use case for an abstract class. You should keep LogBaseViewModel public, and make it abstract.
Related
As you know, C# 9.0 (.Net 5) now allows Covariant Returns. I need help applying this to a set of classes having Auto-Implemented properties.
I have two abstract classes that represent financial bank accounts and transactions. I made them abstract since I will pull data from various data sources and while the main properties will be common across all sources, each source may have additional fields I want to keep. A 1 to Many relationship exists between both classes (1 account has many transactions AND 1 transaction belongs to only 1 account).
public abstract class BankAccount
{
public string Name { get; set; }
public IList<Transaction> Transactions { get; set; } = new List<Transaction>();
...
}
public abstract class Transaction
{
public string Name { get; set; }
public virtual BankAccount BankAccount { get; set; } // This doesn't work unless I remove set;
...
}
And here is an example of the concrete implementations
public class PlaidBankAccount : BankAccount
{
public string PlaidId { get; set; }
...
}
public class PlaidTransaction : Transaction
{
public string PlaidId { get; set; }
public override PlaidBankAccount BankAccount { get; set; } // This doesn't work unless I remove set;
...
}
What I want to do is to override the base class getters and setters so that they use derived classes. For example:
If I create an instance of the concrete transaction and call the BankAccount getter, I want to get an instance of the derived PlaidBankAccount not the base BankAccount.
What I've found is that when I only define virtual getter in the base class and override it in the derived class, it works. But just as I add both properties {get;set;}, I get the same error as in previous C# versions:
error CS1715: 'PlaidTransaction.BankAccount': type must be 'BankAccount' to match overridden member 'Transaction.BankAccount'
How could I fix this?
In C# 9 properties are only able to have co-variant returns when they are readonly, so unfortunately, no set; is possible.
An overriding property declaration must specify exactly the same access modifier, type, and name as the inherited property. Beginning with C# 9.0, read-only overriding properties support covariant return types. The overridden property must be virtual, abstract, or override.
From the Microsoft Docs - Override keyword
I have an app that uses a set of dll's from a 3rdparty. I am trying to incorporate an updated version of the dll's that have changed some variables and parameters from int to uints. I think I can easily capture base class events in my derived class and re-throw modified events, but I am not sure of an easy way to handle the direct access of the variables in the base class's member class.
The example below shows the original 3rd party implementation. In the latest version, the member variables of ThirdPartyNumberPair are now uint's. I'm looking for a way to intercept the MyNumberPair.x and .y access in my derived container and do the conversion so I don't have to modify SomeMethod - mainly because it is used in many places.
public class ThirdPartyNumberPair
{
public int x{ get; set; };
public int y{ get; set; };
}
public class ThirdPartyContainer
{
public ThirdPartyNumberPair MyNumberPair;
}
public class MyDerivedContainer : ThirdPartyContainer
{
...
}
public class MyClass
{
public MyDerivedContainer myContainer;
public void MyMethod(){
int i = myContainer.MyNumberPair.x;
myContainer.MyNumberPair.y = 3;
}
}
I've tried creating a derived MyThirdPartyNumberPair and hiding the base ThirdPartyNumberPair, but I didn't find any easy way of getting those values to the base ThirdPartyNumberPair member.
Trying to find out - is there any difference between:
public member (property, method) in protected class, and
protected member (property, method) in public class. It's not only about public and protected. It's about combination of different access modifiers for members of class.
As I understand - class member's maximum allowed access level is the lowest access level of class or member, whichever is lower.
So, public method in protected class will be accessible only within same or derived class. And same access level will be for protected method in public class.
Are my suggestion correct? Or I missing something?
This question came up from C# quiz where it says:
You are creating a class named Employee. The class exposes a string property named EmployeeType.The following code segment defines the Employee class.
public class Employee
{
internal string EmployeeType { get; set; }
}
The EmployeeType property value must be accessed and modified only by code within the Employee class or within a class derived from the Employee class.You need to ensure that the implementation of the EmployeeType property meets the requirements. How it must be modified?
I selected:
protected string EmployeeType { get; set; }
But correct answer was:
internal string EmployeeType { protected get; protected set; }
So, what is the difference, if in both cases maximum access level of property is protected?
I've the following class:
namespace Warnings
{
public abstract class BaseWarningIntField : IWarningInnerDataField
{
public string PropName;
public string HeaderCaption;
public sealed WarningInnerDataType DataType
{
get { return WarningInnerDataType.Integer; }
}
}
}
I want the last property DataType to be not overridable, since that's the base class for a warning-detail field of type Integer, so it needs to always return the correct type WarningInnerDataType.Integer.
Anyway, the compiler give me the following error:
'Warnings.BaseWarningIntField.DataType' cannot be sealed because it is not an override
But, as far as I know the override does exactly the opposite of what I'm trying to achieve.
in C# all methods by default are non-virtual. You can't override non-virtual method in sub-classes. So leaving property as usual will safe you from subclass overriding it.
Sealed is a keyword used in class declaration for inheritance restrictions or is used to stop virtual chain of members of a class hierarchy. But again - this relates to virtual methods and properties.
Trying to override "normal" property in sub-class will result in compile error
'WarningIntField.DataType.get': cannot override inherited
member 'BaseWarningIntField.DataType.get' because it is not
marked virtual, abstract, or override
To answer you comment, I'll present some code examples to illustrate my point. You can't actually restrict derived classes from hiding a method or property. So next situation is legal and there is no way to overcome it (this related to virtual method and methods denoted with new keyword as well)
class BaseClass
{
public string Property {get; set;}
}
class DerivedClass : BaseClass
{
//compiler will give you a hint here, that you are hiding a base class prop
public string Property {get; set;}
}
The same way you can't restrict of hiding a field in a class by local variable, so this situation is also valid. Note that compiler will also help you to note, that you are hiding class field in by a local variable. This also related to readonly const and simple static fields as well.
int field = 0; //class field
void Foo()
{
int field = 0; //local variable
}
I have an abstract base class for a generic 'Device' type and would like to require the derived specific device classes to initialize a list based on their respective differences.
When one sets the derived class to active it must go through the list to set the parameters to active as well. Each derived class will insert their own parameters into the list.
Here is the relevant code:
Base class:
abstract public class Device : Common, IDisposable
{
abstract public Boolean bActive
{
get;
set;
}
abstract List<Parameters> ActiveParameters;
...
}
I don't wish to initialize the List in the base class because I do not know which parameters are going to be inserted into the list from the derived class. This code produces an error saying that I cannot have an abstract field and I understand that but is there a way to require a derived class to initialize a field from the base class?
This code produces an error saying that I cannot have an abstract field and I understand that but is there a way to require a derived class to initialize a field from the base class?
If this is required to be implemented, it should be part of your API. To handle this, you can make this a protected property. This will force it to be implemented by all derived classes.
protected abstract List<Parameters> ActiveParameters { get; }
If this is about initializing the list, then you can force that by putting that list into the constructor (or all constructors, if you have more of them) of the base class.
Something like:
public abstract class Device : Common, IDisposable
{
protected Device(List<Parameters> activeParameters)
{
ActiveParameters = activeParameters;
}
protected List<Parameters> ActiveParameters { get; private set; }
}
The derived class will be then forced to do something like:
public class ConcreteDevice : Device
{
public ConcreteDevice()
: base(new List<Parameters>())
{}
}