c# hiding method on derived class and using Attributes - c#

I have sample object model as below.
[AttributeUsage(AttributeTargets.Method)]
public sealed class CandidateApiForMenuItem : Attribute
{
public CandidateApiForMenuItem(string caption)
{
this.Caption = caption;
}
public string Caption { get; set; }
}
public class FormDataElementBase
{
public FormDataElementBase()
{
}
[CandidateApiForMenuItem("Add PanelGroup")]
public void AddPanelGroup()
{
///...
}
[CandidateApiForMenuItem("Add BoxGroup")]
public void AddBoxGroup()
{
///...
}
[CandidateApiForMenuItem("Remove")]
public void Remove()
{
///...
}
public void GenerateGroupPopupMenuItems()
{
foreach (MethodInfo methodInfo in this.GetType().GetMethods())
{
if (methodInfo.GetCustomAttribute(typeof(CandidateApiForMenuItem)) != null)
{
// This is true both for FormDataElementBase and all derived
// but I want to hide Remove method inside MainGroup class
// However it is displayed again
};
};
}
}
public class BoxGroup : FormDataElementBase
{
}
public class PanelGroup : FormDataElementBase
{
}
public class MainGroup : FormDataElementBase
{
private void Remove()
{
}
}
When user right click, application will display PopupMenu (GenerateGroupPopupMenuItems method). Items of menu will be based on methods who has CandidateApiForMenuItem declared. However, there are derived class (MainGroup) where some methods (f.e: Remove) should not be displayed. What I did, inside MainGroup declared Remove method as private. However, it is displayed again.
Could you pls let me know what I am doing worng here?
Thanks.

First of all, this.GetType().GetMethods() without parameters returns only public instance (i.e. non-static) methods. So MainGroup.Remove won't be returned by this call.
If you make MainGroup.Remove public, this.GetType().GetMethods() will return both methods - for base class and for derived one. Not what you want, I suppose.
If you make FormDataElementBase.Remove virtual and MainGroup.Remove override, GetMethods will return only one Remove method (with DeclaringType==typeof(MainGroup)) - this is better.
And finally, I'd suggest to introduce one more attribute, say, CandidateApiIgnore. If we mark an overridden method with this attribute and modify in the following way GenerateGroupPopupMenuItems method, the stuff should work:
[AttributeUsage(AttributeTargets.Method)]
public sealed class CandidateApiIgnore : Attribute
{
public CandidateApiIgnore() { }
}
public class FormDataElementBase
{
///...
[CandidateApiForMenuItem("Remove")]
public virtual void Remove()
{
///...
}
public void GenerateGroupPopupMenuItems()
{
foreach (MethodInfo methodInfo in this.GetType().GetMethods())
{
if (methodInfo.GetCustomAttribute(typeof(CandidateApiForMenuItem)) != null &&
methodInfo.GetCustomAttribute(typeof(CandidateApiIgnore)) == null)
{
// If a method is overridden and marked with
// CandidateApiIgnore attribute in a derived
// class, it won't be processed here.
};
};
}
public class MainGroup : FormDataElementBase
{
[CandidateApiIgnore]
public override void Remove()
{
throw new NotSupportedException();
}
}

Related

Intelligent Generic Static Method

I wrote C# code as described below that inherits a class from a generic class with static methods. I want to call the child class for its static methods (inherited from the base class) without having to specify the type.
EDITED! More "real" code
public class Rec
{
public string Name { get; set; }
public override string ToString() { return this.Name; }
public virtual void Load() { /* HERE IT READS A TEXT FILE AND LOAD THE NAME */ }
}
public class BaseClass<T> : Rec
{
public T Argument { get; set; }
public override void Load() { /* NOW IT LOADS ALSO THE ARGUMENT */ }
public static H Method<H>() where H : Rec, new()
{
H iH = new H();
iH.Load();
iH.Name += " " + iH.Argument.ToString();
return iH;
}
}
public class Child : BaseClass<string> { }
public class SomeOtherClass
{
public void Test()
{
Child i = Child.Method();
//instead of Child.Method<Child>();
}
}
So, instead of having to call method<h>() i'd like to just call method(), so the code should assume that "h" is the caller type. Like in:
How can I do it?
Static methods are not inherited in C#
See this answer for an idea of a potential implementation: Stack Overflow whats-the-correct-alternative-to-static-method-inheritance
You could change method<h> to method and make it an instance method:
public class BaseClass<T> where T, new()
{
public T method() { /* RETURN SOMETHING */ }
}
And then call it as follows:
public class ABC : Child
{
public void Test()
{
var iABC = this.method();
}
}

Force override method if another method is overriden

Is there a way to force the override of a virtual method if another method is overriden?
public class BaseClass
{
protected virtual void A()
{
// a default action called first
}
protected virtual void B()
{
// a default action called second that,
// if A was overriden, makes no sense
}
}
EDIT
Thanks a lot for the Answers. It's very interresting to see how this could be achieved, but for my explicit case it's not critically important.
Also, i forgot to mention how those Methods would be used: (in BaseClass)
pulbic bool EditEntity(Guid id)
{
A();
// Some code that edits Entites
B();
}
No, you cannot. But this makes me think how could you achieve the same concept?
The best idea I came up with was declaring an interface which had the package of methods to override.
public interface IMyOverridablePackage
{
void A_Override();
void B_Override();
}
Then give the base class a protected method where the child class can explicitly override the set of methods.
protected void SetOverride(IMyOverridablePackage overridablePackage)
{
_overridablePackage = overridablePackage;
}
So then here's two classes, one which does and one which does not override the set of methods:
public class NotOverriding : MyBaseClass
{
}
public sealed class Overriding : MyBaseClass, IMyOverridablePackage
{
public Overriding()
{
SetOverride(this);
}
void IMyOverridablePackage.A_Override()
{
Console.WriteLine("Overriding.A_Override");
}
void IMyOverridablePackage.B_Override()
{
Console.WriteLine("Overriding.B_Override");
}
}
And the implementation of the base class:
public abstract class MyBaseClass
{
private IMyOverridablePackage _overridablePackage;
public void A()
{
_overridablePackage.A_Override();
}
public void B()
{
_overridablePackage.B_Override();
}
private class MyDefaultPackage : IMyOverridablePackage
{
private readonly MyBaseClass _myBaseClass;
internal MyDefaultPackage(MyBaseClass myBaseClass)
{
_myBaseClass = myBaseClass;
}
void IMyOverridablePackage.A_Override()
{
_myBaseClass.A_Impl();
}
void IMyOverridablePackage.B_Override()
{
_myBaseClass.B_Impl();
}
}
protected MyBaseClass()
{
_overridablePackage = new MyDefaultPackage(this);
}
private void A_Impl()
{
Console.WriteLine("MyBaseClass.A_Impl");
}
private void B_Impl()
{
Console.WriteLine("MyBaseClass.B_Impl");
}
protected void SetOverride(IMyOverridablePackage overridablePackage)
{
_overridablePackage = overridablePackage;
}
}
This does achieve the goal, but of course you have to ask 'how much to I want it?' Is it worth the extra code?
Here's a working dotnetfiddle: https://dotnetfiddle.net/xmPn20
Maybe you cannot force it via compiler errors, but you could write a test which asserts that the methods are in sync via some attributes. It would also be visible that there is some dependency.
A crude example would be something like this:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class VersionAttribute : Attribute
{
public VersionAttribute(string version)
{
Version = version;
}
public string Version { get; set; }
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class DependentAttribute : Attribute
{
public string DependentOnMethod { get; set; }
public string DependentOnVersion { get; set; }
}
[Dependent(DependentOnMethod = "OtherMethod", DependentOnVersion = "1")]
public static void FirstMethod()
{
}
[Version("1")]
public static void OtherMethod()
{
}
And the test that asserts the version numbers:
[Test]
public void TestVersions()
{
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
foreach (var method in type.GetMethods())
{
foreach (var customAttribute in method.GetCustomAttributes())
{
var dependent = customAttribute as DependentAttribute;
if (dependent != null)
{
var methodInfo = type.GetMethod(dependent.DependentOnMethod);
Assert.That(methodInfo, Is.Not.Null, "Dependent method not found");
VersionAttribute version = methodInfo.GetCustomAttributes().OfType<VersionAttribute>().FirstOrDefault();
Assert.That(version, Is.Not.Null, "No version attribute on dependent method");
Assert.That(dependent.DependentOnVersion, Is.EqualTo(version.Version));
}
}
}
}
}
thus, if you update one of your methods you would need to update the version number of either the Version attribute or the Dependent attribute. Hopefully better than nothing.
You may change your design :
public abstract class BaseClass
{
protected abstract void A();
}
public class BaseClassEx
{
protected sealed override void A()
{
// action Calling B
}
protected virtual void B()
{
// a default action called second
}
}
In the case of Equals (actually both Equals overloads, concrete type and object) and GetHashCode, Resharper includes a rule that shows a warning in its IntelliSense whenever you forget to implement one of these.
You could enforce it in your code with a runtime check in the constructor of the base class:
public class Base
{
public Base()
{
var baseA = typeof (Base).GetRuntimeMethod("MethodA", new Type[0]);
var baseB = typeof (Base).GetRuntimeMethod("MethodB", new Type[0]);
var derivedA = GetType().GetRuntimeMethod("MethodA", new Type[0]);
var derivedB = GetType().GetRuntimeMethod("MethodB", new Type[0]);
if (baseA.DeclaringType == derivedA.DeclaringType ^
baseB.DeclaringType == derivedB.DeclaringType)
throw new InvalidOperationException("You must override MethodA and MethodB together.");
}
public virtual string MethodA() { return "Hello"; }
public virtual int MethodB() { return 123; }
}

C# Object Inheritance

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.

how to implement selective property-visibility in c#?

Can we make a property of a class visible to public , but can only be modified by some specific classes?
for example,
// this is the property holder
public class Child
{
public bool IsBeaten { get; set;}
}
// this is the modifier which can set the property of Child instance
public class Father
{
public void BeatChild(Child c)
{
c.IsBeaten = true; // should be no exception
}
}
// this is the observer which can get the property but cannot set.
public class Cat
{
// I want this method always return false.
public bool TryBeatChild(Child c)
{
try
{
c.IsBeaten = true;
return true;
}
catch (Exception)
{
return false;
}
}
// shoud be ok
public void WatchChild(Child c)
{
if( c.IsBeaten )
{
this.Laugh();
}
}
private void Laugh(){}
}
Child is a data class,
Parent is a class that can modify data,
Cat is a class that can only read data.
Is there any way to implement such access control using Property in C#?
Rather than exposing the inner state of the Child class you could provide a method instead:
class Child {
public bool IsBeaten { get; private set; }
public void Beat(Father beater) {
IsBeaten = true;
}
}
class Father {
public void BeatChild(Child child) {
child.Beat(this);
}
}
Then the cat can't beat your child:
class Cat {
public void BeatChild(Child child) {
child.Beat(this); // Does not compile!
}
}
If other people need to be able to beat the child, define an interface they can implement:
interface IChildBeater { }
Then have them implement it:
class Child {
public bool IsBeaten { get; private set; }
public void Beat(IChildBeater beater) {
IsBeaten = true;
}
}
class Mother : IChildBeater { ... }
class Father : IChildBeater { ... }
class BullyFromDownTheStreet : IChildBeater { ... }
This is usually achieved by using separate assemblies and the InternalsVisibleToAttribute. When you mark the set with internal classes within the current assembly will have access to it. By using that attribute, you can give specific other assemblies access to it. Remember by using Reflection it will still always be editable.

Call constant property on class like static?

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.

Categories