I got an abstract base class
public class Base
{
public abstract String Info { get; }
}
and some children.
public class A : Base
{
public override String Info { get { return "A does ..."; } }
}
public class B : Base
{
public override String Info { get { return "B does ..."; } }
}
This is mere a constant but I want to make sure using Base that all classes implement it.
Now I sometimes do not have an object instance but want to access A.Info - this is not possible due it is a instance property.
Is there another way than implementing the same property on instance AND on static level? That would be feel like a duplicate violating DRY programming style.
NEW EDIT: I now see this two solutions:
public class Base
{
public abstract String ClassInfo { get; }
}
public class A : Base
{
public override String ClassInfo { get { return Info; } }
public static String Info { get { return "A does ..."; } }
}
public class B : Base
{
public override String ClassInfo { get { return Info; } }
public static String Info { get { return "In B we do ..."; } }
}
With this I can do with any object of type Base something like object.ClassInfo but also use the value in my factory hardcoded like if(A.Info) return new A(). But I have to implement two properties for the same information in every class.
On the other hand:
public class Base
{
public abstract String ClassInfo { get; }
public static String GetClassInfo<T>() where T : BaseControl, new()
{
T obj = new T();
return obj.ClassInfo;
}
}
public class A : Base
{
public override String ClassInfo { get { return "text A"; } }
}
public class B : Base
{
public override String ClassInfo { get { return "text B"; } }
}
Due to the abstract Base it is made sure that ClassInfo is always implemented. Calls with obj.ClassInfo and Base.GetClassInfo<A>() are okay. But with this every child of Base must have a default constructor without arguments and we loose performance with the unneccessary created instance.
Is there any other idea? Which one would you prefer and why?
If you need specific return results of your static properties, you're better of either
a) Instance properties
2) Attributes
In the example you've already given, you've got an instance of Base, which means you can just make the instance property virtual:
public class Base
{
public virtual string Info { get { return "From Base"; } }
}
public class A : Base
{
public override string Info { get { return "From A"; } }
}
If you wanted to go the attribute route, you define it as such:
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public class InfoAttribute : Attribute
{
public InfoAttribute(string info) { this.Info = info; }
public string Info { get; private set; }
}
[InfoAttribute(Info = "From Base")]
public class Base
{
public string GetInfo()
{
var attr = GetType()
.GetCustomAttributes(typeof(InfoAttribute), true)
.FirstOrDefault();
return (attr == null) ? null : attr.Info;
}
}
[InfoAttribute(Info = "From A")]
public class A : Base { }
If you wanted to call it as a static function call, you could make this change:
public static string GetInfo(Base instance)
{
var attr = instance.GetType()
.GetCustomAttributes(typeof(InfoAttribute), true)
.FirstOrDefault();
return (attr == null) ? null : attr.Info;
}
And then call it as: Base.GetInfo(instance);. All in all, not very elegant!
This is not possible.
static members cannot be virtual or abstract.
You should make an abstract instance property.
Statics can't be overridden. If you truly want to do something like that, you'd want an instance property that is virtual in the base that gets overridden in the subclasses.
Does it compiled? I don't think so. Static cannot be marked as override, virtual or abstract.
Related
I have the following classes, and when I call CreateQuerySettings on the BaseScriptConfigurationList, it returns the new QuerySettings from ConfigurationList, rather than the HierarchicalQuerySettings value in BaseScriptConfigurationList:
public abstract class ConfigurationList<TConfigurationObject, TPropertyEnum>
{
public QuerySettings<TConfigurationObject, TPropertyEnum> CreateQuerySettings()
{
return new QuerySettings<TConfigurationObject, TPropertyEnum>();
}
}
public class BaseScriptConfigurationList : EditableConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
public BaseScriptConfigurationList(ConfigurationManager configurationManager)
: base(configurationManager, InternalAdminObjectType.BaseScript)
{
_BaseScriptPageListWatcher = new ConfigurationList<BaseScriptPageConfiguration, BaseScriptPageConfiguration.Property>.
ConfigurationWatcher(null);
_ConfigurationWatcher.ChildWatchers.Add(_BaseScriptPageListWatcher);
}
public new QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property, BaseScriptQueryChildrenSettings>();
}
}
Edit: I make the call from another class where TConfigurationObjectList is BaseScriptConfigurationList. I've added the constructor to the code above so you can see what it's doing. Please note that EditableConfigurationList inherits from ConfigurationList.
TConfigurationObjectList cl = (TConfigurationObjectList)typeof(TConfigurationObjectList).GetConstructor(new Type[] { typeof(ConfigurationManager) }).Invoke(new object[] { Manager.ConfigurationManager });
var querySettings = cl.CreateQuerySettings();
When I make this call, it goes into the ConfigurationList.CreateQuerySettings method.
How can I hide the CreateQuerySettings method, so that when I call it from the BaseScriptConfigurationList class, I get a HierarchicalQuerySettings object?
The new modifier can be beasty. Note that you are hiding and not overriding in your example. You are not showing that part of the code, but I assume you have this situation:
class Base
{
public static void BaseMethod() { Console.WriteLine("BASE!"); }
}
class Derived : Base
{
// Hides Base.BaseMethod()
new public static void BaseMethod() { Console.WriteLine("DERIVED!"); }
}
Base a = new Base();
a.BaseMethod(); // -> "BASE!"
Base b = new Derived();
b.BaseMethod(); // -> "BASE!"
Derived b = new Derived();
b.BaseMethod(); // -> "DERIVED!"
In BaseScriptConfigurationList.CreateQuerySettings()
you're return type is QuerySettings<T,T> so you will always get that type as a return value, but you are returning a HierarchicalQuerySettings. You can one, change the return type of CreateQuerySettings() to HierarchicalQuerySettings or two, cast the object to its child type "HierarchicalQuerySettings". If you really want to hide it, you can do this:
public class newclass : BaseScriptConfigurationList
{
public new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return (HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property>)base.CreateQuerySettings();
}
}
But that doesn't really seem efficient and i advise against it. Like i said, i maybe missing some other requirement, but based on the info that you gave..
Basically, what I'm seeing (and making assumptions) that TConfigurationObjectList Inhertis from ConfigurationList somewhere along the lines, so on and so forth, all the way up to EditableConfigurationList. since you are dynamically creating an instance of the class TConfigurationObjectList, and calling the method from that point, you will be calling the base ConfigurationList member CreateQuerySettings. You do not have access to the new CreateQuerySettings. If you are creating the class BaseScriptConfigurationList instance at this point, cast the object ((BaseScriptConfigurationList)cl).CreateQuerySettings(). That being said. if you do not know what you have at runtime:
var obj = typeof(TConfigurationObjectList).GetConstructor(new Type[] { typeof(ConfigurationManager) }).Invoke(new object[] { Manager.ConfigurationManager });
var cl = (obj as BaseScriptConfigurationList) ?? (TConfigurationObjectList)obj;
// or do something else
var querySettings = cl.CreateQuerySettings();
Note i am assuming your architecture is roughly set up like this:
public abstract class ConfigurationList<TConfigurationObject, TPropertyEnum>
{
public QuerySettings<TConfigurationObject, TPropertyEnum> CreateQuerySettings()
{
return new QuerySettings<TConfigurationObject, TPropertyEnum>();
}
}
public class TConfigurationObjectList : ConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
}
public class EditableConfigurationList<T, T1> : TConfigurationObjectList
{
protected EditableConfigurationList(ConfigurationManager configurationManager, object baseScript)
{
throw new NotImplementedException();
}
}
public class BaseScriptConfigurationList : EditableConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
public BaseScriptConfigurationList(ConfigurationManager configurationManager)
: base(configurationManager, InternalAdminObjectType.BaseScript)
{
}
public new QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property, BaseScriptQueryChildrenSettings>();
}
}
public class QuerySettings<T, T1>
{
}
public class HierarchicalQuerySettings<T, T1, T2> : QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
}
public class BaseScriptQueryChildrenSettings
{
}
public class BaseScriptPageConfiguration
{
public class Property
{
}
}
public class InternalAdminObjectType
{
public static object BaseScript { get; set; }
}
public class ConfigurationManager
{
}
public class BaseScriptConfiguration
{
public class Property
{
}
}
Create a base interface for the ConfigurationList class (say IConfigurationList) and use this interface as the data type for the variable cl instead of TConfigurationList.
I have next code
class Base
{
public virtual int Prop { get; set; }
}
class Derived : Base
{
public override int Prop { get { return 1; } }
}
//...
Derived obj = new Derived();
int some = obj.Prop; //expected
obj.Prop = 10; //oops it works
The fact that the last line should complile seems not to be so obvious at first sight. In my program I have a situation when overriding some auto-implemented property in a such way would be a solution. I understand that it's not a good approach. What kind of refactoring can I do to avoid such inheritance and to clean my code? Thanks
A derived class has to implement the same interface as its base class - having a public setter be inaccessible from a derived class would break polymorphism.
If Prop needs to be inaccessible to clients, but you need to be able to set its value from within the class itself, you could declare it as:
public virtual int Prop { get; protected set; }
There probably isn't a single answer to this question, as it depends on the model for your specific application. If some derived classes need to allow writes to this property, but others don't, you could either throw an exception on an invalid write and handle it at run time, or perhaps implement the property using a protected backing field and only a getter, and then add a derived class that provides a SetProp() method for those classes that need it.
public class Base
{
protected int prop;
public virtual int Prop { get { return prop; } }
}
public class WriteableBase : Base
{
public virtual void SetProp(int prop) { this.prop = prop; }
}
class Base
{
public virtual int Prop { get; set; }
}
class Derived : Base
{
public new int Prop { get { return 1; } private set {} }
}
The problem is that if you cast your Derived to Base, you can set the property anyway. If the Property relay on a field, it will be overwriten.
Ex.:
class Base
{
protected int fProp;
public virtual int Prop { get { return fProp; } set { fProp = value; } }
}
class Derived : Base
{
public Derived()
{
fProp = 1;
}
public new int Prop { get { return fProp; } private set {} }
}
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
//...
Derived obj = new Derived();
int some = obj.Prop; //expected
Base b = (Base)obj;
b.Prop = 10; //oops it works
Console.WriteLine(obj.Prop); =>it will show 10, not 1
Console.ReadKey();
}
}
}
A "better" approach to avoid this kind of problem is to avoid the use of a base class if you want to "change" something on a derived class. Or, put only the minimal content that must be implemente by ALL derived classes and let the derived classes implement any extra code that only they want.
Ex:
class Base
{
protected int fProp;
}
class Derived : Base
{
public Derived()
{
fProp = 1;
}
public int Prop { get { return fProp; } }
}
class Derived2 : Base
{
public int Prop { get { return fProp; } set { fProp = value; } }
}
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
//...
Derived obj = new Derived();
int some = obj.Prop; //expected
Base b = (Base)obj;
//obj.Prop = 10; Compilation error
Console.WriteLine(obj.Prop);
Derived2 obj2 = new Derived2();
obj2.Prop = 10;
Console.WriteLine(obj2.Prop);
Console.ReadKey();
}
}
}
Also, you could "encapsulate" your base class:
class Derived
{
protected Base fBase;
public Derived()
{
fBase = new Base;
}
//implement enything that you need to access from Base class
public int Prop { get { return 1; } }
}
But I find this last one too "expensive"... :)
I think it´s not possible to get compiler-error in this case. Imagine further you´d declare obj not as Derived but as Base = new Derived(), how should compiler know which property to infer. So all you can do is to throw an exception during runtime within the derived setter telling that setting this property isn´t allowed fir this type.
class Base
{
public virtual int Prop { get; protected set; }
}
class Derived : Base
{
public override int Prop {
get { return 1; }
protected set {throw NotSupportedException();}
}
}
When compiling, C# transforms the getter and setter to individual methods (get_Prop and set_Prop).
Your code only implements the get in the Derived class, and the setremains that of the base class.
If this is your desired behavior, I don't find it to be wrong.
If you are trying to hide the setter in the Derived class, there is no elegant way to do it, so throwing an NotSupportedException is a solution.
class Base
{
public virtual int Prop { get; set; }
}
class Derived : Base
{
public override int Prop { get { return 1; } set { throw new NotSupportedException();}}
}
I am trying to create a base class in c# that I can extend out to sub classes.
For example:
public class ObjectsInTheSky
{
public string Size, Shape;
public float Mass;
public int DistanceFromEarth;
public bool hasAtmosphere, hasLife;
public enum ObjectTypes {Planets,Stars,Moons}
public ObjectsInTheSky( int id )
{
this.Load( id );
}
public void Load( int id)
{
DataTable table = Get.DataTable.From.DataBase(id);
System.Reflection.PropertyInfo[] propInfo = this.GetType().GetProperties();
Type tp = this.GetType();
foreach (System.Reflection.PropertyInfo info in propInfo)
{
PropertyInfo p = tp.GetProperty(info.Name);
try
{
if (info.PropertyType.Name == "String")
{
p.SetValue(this, table.Rows[0][info.Name].ToString(), null);
}
else if (info.PropertyType.Name == "DateTime")
{
p.SetValue(this, (DateTime)table.Rows[0][info.Name], null);
}
else
{
p.SetValue(this, Convert.ToInt32(table.Rows[0][info.Name]), null);
}
}
catch (Exception e)
{
Console.Write(e.ToString());
}
}
}
}
public class Planets : ObjectsInTheSky
{
public Moons[] moons;
}
public class Moons : ObjectsInTheSky
{
}
public class Stars : ObjectsInTheSky
{
public StarTypes type;
public enum StarTypes {Binary,Pulsar,RedGiant}
}
My problem is when I try to use an object:
Stars star = new Stars(142);
star.type does not exists and property of star, it exists as star.star.type but completely inaccessable, or I can not figure out how to access it.
I do not know if I'm extending the ObjectsInTheSky property properly or not. Any help or pointers will be greatly appreciated.
It looks as though you are trying to use a constructor that is not defined on your subclass Stars or the base class.
Stars star = new Stars(142);
If you are trying to use the .Load(int) method then you would need to do this:
Stars star = new Stars();
star.Load(142);
Or, if you are trying to use the base constructor, you need to define it in the subclass:
public class Stars : ObjectsInTheSky
{
public Stars(int id) : base(id) // base class's constructor passing in the id value
{
}
public Stars() // in order to not break the code above
{
}
public StarTypes type;
public enum StarTypes {Binary,Pulsar,RedGiant}
}
Constructors in C# are not inherited. You need to add the additional constructor overloads to each of the base classes:
public class Stars : ObjectsInTheSky
{
public Stars(int id) : base(id) { }
public StarTypes type;
public enum StarTypes {Binary,Pulsar,RedGiant}
}
This will create a constructor that just calls the base class's constructor for you.
I have the (pseudo) code:
public class GlobalClass
{
public GlobalClass()
{
var x = this.GetType().Name // Returns "Channels"
// WHAT TO DO HERE?
}
}
public class BaseClass
{
public string Title { get; set; }
}
And using this code:
public class Channels : GlobalClass
{
public Channels()
{
}
public class Channel : BaseClass
{
}
}
Where the comment is (// WHAT TO DO HERE?), I want to get the runtime type of BaseClass,
where in my sample code should return Channel.
I am open to different approaches, but only if it's accompanied with an explanation why I should change the code.
I think you need a generic class here, something like:
public class GlobalClass<T> where T : BaseClass
{
public GlobalClass()
{
var theType = typeof(T); //you got it
}
}
public class BaseClass
{
public string Title { get; set; }
}
public class Channel : BaseClass { }
public class Channels : GlobalClass<Channel> { }
You can use reflection like this:
using System.Reflection;
...
public class GlobalClass
{
public GlobalClass()
{
Type[] types = Assembly.GetExecutingAssembly ().GetTypes ();
foreach ( Type t in types )
{
if ( t.BaseType == typeof ( BaseClass ) )
{
Console.WriteLine ( "I found a class " + t.Name + " that subclass BaseClass" );
}
}
}
}
See also Stack Overflow question List of classes in an assembly.
is operator is just for that purpose.
getType() method with class Type can also be used.
class Example
{
static void ShowTypeInfo (object o)
{
Console.WriteLine ("type name = {0},
full type name = {1}", o.GetType(),
o.GetType().FullName );
}
public static void Main()
{
long longType = 99;
Example example= new Example();
ShowTypeInfo (example);
ShowTypeInfo (longType);
}
}
To get the runtime type of anything, you first need an object instance to get the type from. So with your given structure, that's not possible.
There are two possible approaches:
Add a BaseClass parameter to the constructor of your GlobalClass:
public class GlobalClass
{
public GlobalClass(BaseClass data)
{
var dataType = data == null ? null : data.GetType();
// do something with the type
}
}
public class Channels : GlobalClass
{
public Channels(Channel data) : base(data)
{
}
public class Channel : BaseClass
{
}
}
Pass the type to the constructor directly:
public class GlobalClass
{
public GlobalClass(Type actualType)
{
Debug.Assert(typeof(BaseClass).IsAssignableFrom(actualType));
}
}
public class Channels : GlobalClass
{
public Channels() : base(typeof(Channel))
{
}
public class Channel : BaseClass
{
}
}
If the structure for some reason doesn't allow generics here (as Danny Chen suggested), I'd personally prefer the second approach, since that doesn't need an actual instance.
I need a base class with a property where I can derive classes with the same property but different (compatible) types. The base Class can be abstract.
public class Base
{
public virtual object prop { get; set; }
}
public class StrBase : Base
{
public override string prop { get; set; } // compiler error
}
public class UseIt
{
public void use()
{
List<Base> l = new List<Base>();
//...
}
}
I tried it with Generics but that gives me a problem when using the class, because I want to store differently typed base classes in the List.
public class BaseG<T>
{
public T prop { get; set; }
}
public class UseIt
{
public void use()
{
List<BaseG> l = new List<BaseG>(); // requires type argument
//...
}
}
Here's an alternative approach to proposed solution:
public abstract class Base
{
public abstract void Use();
public abstract object GetProp();
}
public abstract class GenericBase<T> : Base
{
public T Prop { get; set; }
public override object GetProp()
{
return Prop;
}
}
public class StrBase : GenericBase<string>
{
public override void Use()
{
Console.WriteLine("Using string: {0}", Prop);
}
}
public class IntBase : GenericBase<int>
{
public override void Use()
{
Console.WriteLine("Using int: {0}", Prop);
}
}
Basically I've added a generic class in the middle that stores your properly-typed property. this will work assuming that you never need to access Prop from the code that iterates the members of the List<Base>. (You could always add an abstract method to Base called GetProp that casts the generic to an object if that's required.)
Sample usage:
class Program
{
static void Main(string[] args)
{
List<Base> l = new List<Base>();
l.Add(new StrBase {Prop = "foo"});
l.Add(new IntBase {Prop = 42});
Console.WriteLine("Using each item");
foreach (var o in l)
{
o.Use();
}
Console.WriteLine("Done");
Console.ReadKey();
}
}
Edit: Added the GetProp() method to illustrate how the property can be directly accessed from the base class.
You can't override the type of a property. Take a look at the following code:
StrBase s = new StrBase();
Base b = s;
This is completely valid code. But what happens when you try to do this?
b.prop = 5;
The integer can be converted to object, because everything is derived from object. But since b is actually a StrBase instance, it would have to convert the integer to a string somehow, which it can't. So that is why you aren't allowed to override the type.
The same principle applies to generics:
List<BaseG<object>> l = new List<BaseG<object>>();
BaseG<string> s = new BaseG<string>();
// The compiler will not allow this.
l.add(s);
// Here's the same problem, convert integer to string?
BaseG<object> o = l[0];
o.prop = 5;
This is because generic types in C# 2.0 are invariant. C# 4.0 does allow this type of conversions, called covariance and contravariance.
Solutions
An option is to cast the object back to string when you need it. You could add type validation in the subclass:
public class StrBase : Base
{
private string propValue;
public override object prop {
get
{
return this.propValue;
}
set
{
if (value is string)
{
this.propValue = (string)value;
}
}
}
}
You could also expose a type-safe property in the subclass:
public class StrBase : Base
{
public string strProp {
get
{
return (string)this.prop;
}
set
{
this.prop = value;
}
}
}
This is possible since C# 9.0
Beginning with C# 9.0, override methods support covariant return types.
(see Microsoft docs)
public class First
{
private int someV;
public virtual object SomeV { get => someV; set => someV = (int)value; }
public First() { }
}
public class Two : First
{
private string someV;
public override object SomeV { get => someV; set => someV = value.ToString(); }
public Two() { }
}
and use of those:
First firstClass = new First();
firstClass.SomeV = 1;
Two twoClass = new Two();
twoClass.SomeV = "abcd";