Overrideable property that can be accessed both by instance and by class - c#

I have an inheritance tree with a bunch of different classes. Each of these classes has some static properties that I need acces to from time to time. Sometimes I need the property of a particular class, and sometimes I need the property of the specific class some polymorphic instance turns out to be.
This would be easy in, say, Java (I think). Just make a bunch of static fields (can these be overriden? I'm not sure). But in C#, non-static fields can ONLY be accessed via an instance (naturally), and static fields can ONLY be accessed via their corresponding class (unnaturally).
And, you can't "overload" by, er, staticity. If a class has a static and a non static Foo, doing instance.Foo fails because it is unclear to the compiler which Foo you're referring to even though it's impossible you're referring to the static one since it's disallowed.
Ok, I'll provide some code. Say I have this:
class Base
{
public static readonly string Property = "Base";
}
class Child1 : Base
{
public static readonly new string Property = "Child 1";
}
class Child2 : Base
{
public static readonly new string Property = "Child 2";
}
And then, somewhere:
public void SomeMethod(Base instance)
{
System.Console.WriteLine(instance.Property); // This doesn't work.
}
And somewhere else:
public void SomeOtherMethod()
{
System.Console.WriteLine(Child2.Property);
}
I want something like that, that actually works.

As Peter Duniho said, this can be done with reflection.
For example, these can be defined within the base class:
public const string Property = "Base";
public virtual string InstanceProperty
{
get
{
return (string)this.GetType()
.GetField("Property", BindingFlags.Public | BindingFlags.Static)
.GetValue(null);
}
}
And then each derived class just has to redefine Property using the new keyword.

I think the best you'll do in C# is something like this:
public class BaseClass
{
public virtual string InstanceProperty
{
get { return StaticProperty; }
}
public static string StaticProperty
{
get { return "BaseClass"; }
}
}
public class Derived1Base : BaseClass
{
public override string InstanceProperty
{
get { return StaticProperty; }
}
public new static string StaticProperty
{
get { return "Derived1Base"; }
}
}
public class Derived1Derived1Base : Derived1Base
{
}
public class Derived2Base : BaseClass
{
public override string InstanceProperty
{
get { return StaticProperty; }
}
public new static string StaticProperty
{
get { return "Derived2Base"; }
}
}

Related

Why can't I access a constant from an object?

public class Foo
{
public const int type = 1;
}
Why can't i do this? Is there a reason behind it or am I trying to access the constant in a wrong way?
new Foo().type;
I know I can do Foo.type but given my scenario, I cant do that. For example if I have two class which inherit from a base class like this:
public class Base
{
...
}
public class Foo : Base
{
public const int type = 0;
}
public class Bar : Base
{
public const int type = 1;
}
public static void printType(Base b)
{
Console.WriteLine(b.type);
}
I would want to get the type property of the class sent through the printType() function but I cant since I can only access the type from the Class, not the object its self.
A work around would be to do
if(b is Foo){
Console.Write(Foo.type);
}elseif....
but this seems stupid and not viable if you have many sub classes of Base
Solution
I ended up using readonly instead of const like this:
public readonly int type = 0;
Yes, you're trying to access it in the wrong way. A constant isn't associated with an instance of a type - it's associated with the type itself. So you want:
int x = Foo.type;
Basically, const members are implicitly static, and C# doesn't let you access static members as if they were instance members, via a value. (Note that in .NET naming conventions, it should be Type rather than type.)
EDIT: Now that you've explained the actual situation, it appears you're trying to use polymorphism, which won't work for constants. So instead, you should have an abstract property in the base class, implemented in subclasses.
public abstract class Base
{
public abstract int Type { get; }
}
public class Foo : Base
{
public override int Type { get { return 0; } }
}
public class Bar : Base
{
public override int Type { get { return 0; } }
}
Alternatively, just have a normal property in the base class which is populated via the base class constructor:
public class Base
{
private readonly int type;
public int Type { get { return type; } }
protected Base(int type)
{
this.type = type;
}
}
public class Foo : Base
{
public Foo() : base(0) {}
}
public class Bar : Base
{
public Bar() : base(1) {}
}
If you just want something to identify the dynamic (most-derived) type of the object passed in, that's built into .NET, via the Object.GetType() method.
public static void printType(Base b)
{
Console.WriteLine(b.GetType().Name);
}
Of course, this isn't quite the same as having attached data under your control. You can, however, use a Dictionary<Type, T> to associate data of arbitrary type with the various subclasses. It would be reasonable to use the subclass type initializer to install new entries into such a dictionary.
public class Base
{
static internal readonly Dictionary<System.Type, int> TypeMap =
new Dictionary<System.Type, int>();
}
public class Foo : Base
{
static Foo { TypeMap.Add(typeof(Foo), 0); }
}
public class Bar : Base
{
static Bar { TypeMap.Add(typeof(Bar), 1); }
}
public static void printType(Base b)
{
Console.WriteLine(Base.TypeMap[b.GetType()]);
}
This WILL be a bit slower than the field-per-object method, however it doesn't add any extra storage per-object.

Base Class Used With Types, Possible to Assign Generically?

Assuming the following code:
public class Shared
{
public string String1 { get; set; }
}
public class ImplementedOne : Shared{}
public class ImplementedTwo : Shared{}
public T SetBaseProperties<T>(Shared shared)
{
// go through and assign, return type ImplementedOne or ImplementedTwo
}
I have two objects inheriting from Shared, ImplementedOne and ImplementedTwo. Each of these uses the property String1, however it can vary between the object instances. Since both of them inherit the base class, can I have a generic method that assigns these common properties?
If you are looking for a place to initialize the String1 property it should be in the base class constructor
public class Shared
{
public string String1 { get; set; }
public Shared(string str)
{
String1 = str;
}
}
And than just
public class ImplementedOne : Shared
{
public ImplementedOne() : base("your string")
{
}
}
I suggest either implementing a method in Shared to set its properties:
public class Shared
{
public void SetProperties( Shared shared )
{
this.String1 = shared.String1;
}
}
Or creating a copy constructor for Shared that is called by derived classes' constructors that accept an instance of Shared (this is my preferred method):
public class Shared
{
public Shared( Shared source )
{
this.String1 = source.String1;
}
}
public class ImplementedOne : Shared
{
public ImplementedOne( Shared source ) : base( source )
{
}
}
Update:
I may have misunderstood your question - if you're asking how to assign a single property to the same value for each instance of derived type, I would make the property virtual and implement on a per class basis:
public class Shared
{
public virtual string String1 { get { return "Shared's string"; } }
}
public class ImplementedOne : Shared
{
public override string String1 { get { return "ImplementedOne's string"; } }
}
public class ImplementedTwo : Shared
{
public override string String1 { get { return "ImplementedTwo's string"; } }
}
I think you are missing the point about generics...
In your particular case you just need a method in the Shared class that sets the property String1, String2...
public class Shared
{
public string String1 { get; set; }
public SetBaseProperties()
{
// go through and assign, return type ImplementedOne or ImplementedTwo
}
}
which you can use on either ImplementationX class,
var implementation1 = new Implementation1();
implementation1.SetBaseProperties();
Although, of course, this is something you would put in a construtor,
public class Shared
{
public Shared()
{
this.SetBaseProperties();
}
public string String1 { get; set; }
public SetBaseProperties()
{
// go through and assign, return type ImplementedOne or ImplementedTwo
}
}
If you really want to use a generic method to modify the types, you can use a generic constraint.
public T SetBaseProperties<T>(T object) where T : Shared
{
object.String1 = "value";
return object;
}
But it seems overkill for what you want. I would just go with what Tomek suggested.

How can I wrap static properties of a base class so that they return a sub class object?

Say I have code out there like this:
public class Base // I cannot change this class
{
public string Something { get; private set; }
public string Otherthing { get; set; }
public static Base StaticPreSet
{
get { return new Base { Something = "Some", Otherthing = "Other"}; }
}
public static Base StaticPreSet2
{
get { return new Base { Something = "Some 2", Otherthing = "Other 2"}; }
}
}
public class SubClass : Base // I can change this class all I want.
{
public string MoreData { get; set; }
// How can I wrap the PreSets here so that they return SubClass objects?
// Something like this:
public static SubClass MyWrappedPreset
{
get
{
// Code here to call the base preset and then use it as the
// base of my SubClass instance.
}
}
}
What makes this complicated is the Something property. It has a private setter. So I can't set it in the subclass. The only way it can be set is is via the preset properties.
Is there a way to wrap the StaticPreSet property in my SubClass so that it will return an object of type SubClass?
// I cannot change this base class.
Given that you can't change the base class, there is no way to cause it to change behavior (ie: return a different class at runtime).
If you could influence the design of the base class static methods, you could redesign it in a way to be flexible enough to provide this functionality. However, without changing it, this won't work.
Edit in response to edit:
You could create a new static method that does what you are showing, like so:
public static SubClass MyWrappedPreset
{
get
{
// Code here to call the base preset and then use it as the
// base of my SubClass instance.
Base baseInstance = Base.StaticPreSet;
SubClass sc = new SubClass(baseInstance); // Create a new instance from your base class
return sc;
}
}
However, this provides a completely new, unrelated property - you'd have to access it via SubClass.MyWrappedPreset, not the Base class.
Static fields in a class "have nothing to do with it".
Basically, except access to private static fields, id doesn't matter in which class you put them - they behave the same.
If you inherit a class, and you declare another static field with the same name of a static field on the base class, you will simply 'hide' it. Example for you:
using System;
public class Base // I cannot change this class
{
public string Something { get; set; }
public string Otherthing { get; set; }
public static Base StaticPreSet
{
get { return new Base { Something = "Some", Otherthing = "Other"}; }
}
public static Base StaticPreSet2
{
get { return new Base { Something = "Some 2", Otherthing = "Other 2"}; }
}
}
public class SubClass : Base // I can change this class all I want.
{
public string MoreData { get; set; }
public static SubClass StaticPreSet2
{
get { return new SubClass { Something = "inherited", Otherthing=""}; }
}
}
public class Test
{
public static void Main()
{
Console.WriteLine(SubClass.StaticPreSet2.Something);
}
}
Will write "inherited".

Can I define a property which is available to both the class type and instances of the class?

I have an interface for a base class, and every class that inherits from the base class should have an identifying field which tells the application what kind of object it is.
I wanted to use this property in two different ways:
Without creating an instance of the object
if (someValue == TestA.Id)
return new TestA();
elseif (someValue == TestB.Id)
return new TestB();
And as a property of the interface
void DoSomething(ITest testObject)
{
SomeValue = testObject.Id;
}
Is there an easy way to define the Id field in the interface, but still have it available to use without creating an instance of the class?
Right now I am using the following code. I could add a read-only Id property to the interface which returns the const string, however I was hoping there was a simpler way that I'm just not aware of.
public interface ITest
{
}
public class TestA : ITest
{
public const string Id = "A";
}
In short - no.
In order to be able to do this, you'd need to be able to specify this as a instance property on the interface (and implement it in the instance), and as a static property on the type.
The compiler won't let you do this.
You can put it in the interface, and also have it as a static property. Something like:
interface IInterface { Id { get; } }
class Class : IInterface
{
public static Id { get { return 1; } }
public Id { get { return Class.Id; } }
}
I've faced a similar problem, Rachel, and I've always (unfortunately) resorted to having that factory code rely on reflection to get a "TypeID" public static property on each concrete type... thus making an additional aspect of the contractual interface, but not having it in the C# interface code.
You could do it this way.
public interface ITest
{
SomeValue Id{ get;}
}
public class TestA : ITest
{
public SomeValue Id
{
get {return TestA.StaicId; }
}
public static SomeValue StaticId
{
get {return "This is TestA";}
}
}
if (someValue == TestA.StaticId)
return new TestA();
How about using attributes? Here's a small example of what can be done:
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class IdAttribute : Attribute
{
public IdAttribute(string id)
{
this.Id = id;
}
public string Id { get; set; }
}
public interface IMyInterface
{
}
public abstract class BaseClass : IMyInterface
{
public static string GetId<T>() where T : IMyInterface
{
return ((IdAttribute)typeof(T).GetCustomAttributes(typeof(IdAttribute), true)[0]).Id;
}
}
[Id("A")]
public class ImplA : BaseClass
{
}
[Id("B")]
public class ImplB : BaseClass
{
}
internal class Program
{
private static void Main(string[] args)
{
var val1 = BaseClass.GetId<ImplA>();
var val2 = BaseClass.GetId<ImplB>();
Console.ReadKey();
}
}

Populate base class along with child class?

I have a need where I have to add some new fields to an existing class along with all its existing fields/attributes.
So whenever my derived class is filled by DAL, I will be filling all fields of base class as well. Currently, I am doing it like this but not sure this is the right way ? Please give me an example. Also I am not sure whether the base class object will be a new one each time a derived class is initialized ?
public class Employee
{
private int _id;
private int _name;
public int ID
{
set { _id=value;}
get { return _id;}
}
public int Name
{
set { _name=value;}
get { return _name;}
}
protected void SetName ()
{
_name=value;
}
protected void SetID()
{
_id=value;
}
}
public class EmployeeWithDepartmentName:Employee
{
private string _deptName;
public string DeptName
{
set { _deptName=value; }
}
public setBaseEmpName()
{
base.SetName();
}
public setBaseID()
{
base.SetID();
}
}
Everything in a base class can automagically be accessed from derived classes without doiing anything, just use the property/method name directly.
public class MyBase
{
public string UserName {get;set;}
}
public class MyClass : MyBase
{
public void DoSomething()
{
Console.WriteLine("UserName: {0}", UserName);
UserName = "Anders";
}
}
You can also do this:
MyClass myClass = new MyClass();
myClass.UserName = "Rune";
Protected means that only derived classes can access the property/method. Public means that everyone can access the properties/methods.
Also I am not sure whether the base class object will be a new one each time a derived class is initialized ?
It's not two objects, it's one object created from two different classes (that's how inheritance works).
Read this article about inheritance: http://www.csharp-station.com/Tutorials/lesson08.aspx

Categories