Action delegate parameters do not match using implemented abstract class - c#

I have the following abstract class:
public abstract class BaseClass{
public object contents { get; set; }
public Action<BaseClass> mutator;
public abstract void Initialise();
}
This will be used by several classes, which will override the Initialize method to assign a value to contents, which will in turn be mutated using the mutator delegate at specific points in time.
I have the following static class, with each method intended to be used as a mutator:
public static class Mutators{
public static void VariantA(A inputObj){
// inputObj.contents = something else
}
public static void VariantB(A inputObj) { } // etc. etc.
}
I then have class A, which implements BaseClass. I am trying to assign Mutators.VariantA to the mutator delegate, but i'm not able to.
public class A : BaseClass{
public A(){
mutator = Mutators.VariantA;
}
public override void Initialise(){
/* set the value of contents property here */
}
}
Specifically I get the following error: A method or delegateMutators.VariantA(A)' parameters do not match delegate System.Action<BaseClass>(BaseClass)' parameters (CS0123)
I understand that Mutators.VariantA(A) requires an object of type A, and the Action was declared to accept an input of type BaseClass, however as class A implements BaseClass I thought I would have been able to do this ?
Coming from dynamically typed languages i'm having a tough time getting to grips with working with types in this way :(
Is there any way I can point to a function with an input of the abstract type in this way ? Do I need to look at some other design pattern ?
Thanks

I understand that Mutators.VariantA(A) requires an object of type A, and the Action was declared to accept an input of type BaseClass, however as class A implements BaseClass I thought I would have been able to do this ?
Absolutely not.
An Action<BaseClass> has to be able to accept any BaseClass object. So for example, if your code were valid, I would be able to write:
Action<BaseClass> mutator = Mutators.VariantA;
mutator.Invoke(new B());
(Where B is another class derived from BaseClass.)
The fact that B derives from BaseClass makes it valid for the invocation - but it's not going to help your VariantA method work nicely.
It's not really clear why you have a mutator here - I strongly suspect you should abstract BaseClass from its mutations. I still don't follow what you're trying to achieve, but this design pattern isn't going to help you get there in a type-safe way.
You could write:
public abstract class BaseClass<T> where T : BaseClass<T> {
public object Contents { get; set; }
public Action<T> Mutator { get; set; }
public abstract void Initialise();
}
... then:
public class A : BaseClass<A> {
public A() {
Mutator = Mutators.VariantA;
}
}
... as then you'd be writing something which can mutate "A" values. But in my experience this sort of generic nesting gets really messy, really quickly.

I've used your current example and changed the Method Signature of one of the classes to the following and it works
public abstract class BaseClass
{
public object contents { get; set; }
public Action<BaseClass> mutator;
public abstract void Initialise();
}
public static class Mutators
{
public static void VariantA(BaseClass baseClass)
{
// inputObj.contents = something else
}
public static void VariantB(A inputObj) { } // etc. etc.
}
public class A : BaseClass
{
public A()
{
mutator = Mutators.VariantA;
}
public override void Initialise()
{
/* set the value of contents property here */
}
}

Related

Cannot access inherited property if class has nested class of same name

I want to access a property of some class of mine, but get compiler error "CS0572 - Cannot reference a type through an expression".
I have the following setup
public interface IHelper {
void DoHelp();
}
public abstract class ClassWithHelperBase<THelper> where THelper : IHelper {
public THelper Helper { get; }
}
public class ClassWithHelper : ClassWithHelperBase<ClassWithHelper.Helper> {
// use a nested class, since there will be n classes deriving from ClassWithHelper and giving each helper a readable name (in this example ClassWithHelperHelper) is ugly
public class Helper : IHelper {
public static void SomeStaticMethod() { }
public void DoHelp() { }
}
}
public class Test {
private ClassWithHelper myClass;
public void DoTest() {
((ClassWithHelperBase<ClassWithHelper.Helper>) myClass).Helper.DoHelp(); // this works, but is ugly
myClass.Helper.DoHelp(); // what I want, but it's not working
//myClass.Helper.SomeStaticMethod(); // funnily IDE supposes static methods here even though the resulting code is invalid, since I am (obviously) not referencing the class type
}
}
The interface is unnecessary for reproduction, I added it for clarity.
Note: I do not want to call a static method, I just added it, to show the IDE mixes up the member and the class qualifier.
Is there a way to access the property Helper of myClass, without casting myClass or renaming the nested class?
Aka: Why can't the compiler distinguish the member and the nested class?
The problems is due to name collision between Helper class (type) and Helper property. Try this
public interface IHelper
{
void DoHelp();
}
public abstract class ClassWithHelperBase<THelper> where THelper : IHelper
{
public THelper Helper { get; set; }
}
public class ClassWithHelper : ClassWithHelperBase<ClassWithHelper.CHelper>
{
// use a nested class, since there will be n classes deriving from ClassWithHelper and giving each helper a readable name (in this example ClassWithHelperHelper) is ugly
public class CHelper : IHelper
{
public static void SomeStaticMethod() {}
public void DoHelp() { }
}
}
public class Test
{
private ClassWithHelper myClass;
public void DoTest() {
myClass.Helper.DoHelp();
ClassWithHelper.CHelper.SomeStaticMethod();
}
}
Here I renamed Helper class to the CHelper, so compiler can now distinguish class and property and thus the line myClass.Helper.DoHelp(); now works without cast.
If a "do not rename nested class" requirement is absolutely mandatory, then the problem may be also solved by renaming the Helper property in the base class to avoid name collision. However, I can't imagine better name for the property.
Unfortunately, for the static method, you can't reference myClass instance. So, you will need reference the whole type.

C# abstract generic method call

With the abstract following class:
public abstract class A
{
public static string MyMethod()
{
return "a";
}
}
Why can't I built this derived abstract class:
public class B<T> where T : A
{
public void AnotherMethod()
{
var S1 = base.MyMethod(); // not allowed
var S2 = T.MyMethod(); // not allowed
}
}
I don't understand why since MyMethod will be available in type T.
There are two misconceptions in your question that collectively prevent both your attempts from working.
First your B class is not in any way derived from the A class, you have only said that it takes a generic parameter that must inherit from A.
Second as the user #recursive pointed out, static methods do not participate in inheritance so MyMethod would only ever be available as A.MyMethod()
You can make at least your first attempt work if you remove the static modifier and make B inherit from A instead of using generics.
// Removed the static modifier
public abstract class A
{
public string MyMethod()
{
return "a";
}
}
// Made B inherit directly from A
public class B : A
{
public void AnotherMethod()
{
var S1 = base.MyMethod(); //base technically isn't required
}
}
Aside from the fact that A.MyMethod is static, which clearly will not work since anything static does not take part in inheritance, even if you made it not static it still will not work. For example, this will not work either:
public abstract class A {
public string MyMethod() {
return "a";
}
}
public class B<T> where T : A {
public void AnotherMethod() {
var S1 = base.MyMethod(); // Line 1
var S2 = T.MyMethod(); // Line 2
}
}
Why?
You are saying where T : A which means that type T has to be a derived type from A. Your class B<T is not a derived type of A so Line 1 will not work.
But why is Line 2 not working?
T is a type and if T is inheriting A, then objects of type T will be able to do that. If you changed it like this, then it will work:
public abstract class A {
public string MyMethod() {
return "a";
}
}
public class B<T> where T : A {
public void AnotherMethod(T t) {
t.MyMethod();
}
}
public class C : A {
}
public class BClosed : B<C> {
public void Foo(C c) {
c.MyMethod();
this.AnotherMethod(c);
}
}
In the above code, C derives A which was your restriction. Then BClosed closes the generic type saying T is C so now you can call MyMethod of A and AnotherMethod of your generic.
Also, when you have a generic class you should use the generic type otherwise I do not see the use. So this is useless since it has no generic code:
public class B<T> where T : A {
public void AnotherMethod() {
}
}

Solving virtual member call in constructor

I have an abstract class:
public abstract class ExampleBase : IExampleBase
{
protected ExampleBase()
{
this.SetupData();
}
protected abstract Dictionary<int, Adress> RelevantData { get; set; }
protected abstract void SetupData();
public void ProcessData()
{
// use RelevantData
}
}
And a derived class:
public class Example : ExampleBase
{
public Example()
{
}
protected override void SetupData()
{
this.RelevantData = new Dictionary<int, Adress>
{ 1, new Adress { ... } },
{ 2, new Adress { ... } }
}
}
In the base class, ReSharper tells me
Virtual member call in constructor
I understand that it's dangerous to call the method because of the execution order.. but how can I resolve this issue?
Context: I want to set up data in each derived class which will then be processed in the base class. I wanted to call the SetupData() method in the base class since it's the same in every derived class.
Derived class:
Set up the data
Base class:
Process the data
You don't. You accept the fact this is dangerous, and (try to) prevent this. This is a design flaw!
You could prevent this for example by moving the call to the highest level class, or make every class responsible for it's own, thus removing the unsafe part of the method call. Then you don't need another class (a base class) to take responsibility for its deriving classes.
If that isn't possible. Make very clear using comments or any other method available that the developer should take this problem into account when updating the code.
Call SetupData in the constructor of Example (and every other derived class) not ExampleBase and make Example a sealed class.
The problem is that SetupData could access something that would be initialized by the Example constructor. But the Example constructor is called only after ExampleBase constructor has finished.
Your base class constructor is called first. If your override method in your subclass depends on anything done in its constructor it won't work. Personally I'd look for a different design, maybe passing the abstract class into the derived class rather than using inheritance.
So a couple lines of code in every derived class
If you need to control the process order then you can do this
public abstract class MyBase
{
public void ProcessData()
{
bool processData = true;
}
public MyBase()
{
bool myBase = true;
}
public MyBase(int pass)
{
bool myBase = true;
}
}
public class Example : MyBase
{
public void GetData() {}
public Example()
: base(1)
{
bool example = true;
GetData();
ProcessData();
}
}

Force a child class to pass itself as the Generic parameter to the base class

I want to force my child classes to pass themselves as as the generic parameter to the parent class.
For example :
class BaseClass<T> where T: BaseClass
{
//FullClassName : Tuple [Save,Update,Delete]
Dictionary<string,Tuple<delegate,delegate,delegate>> dict = new Dictionary...;
static BaseClass()
{
RegisterType();
}
private static void RegisterType()
{
Type t = typeof(T);
var props = t.GetProperties().Where(/* Read all properties with the SomeCustomAttribute */);
/* Create the delegates using expression trees and add the final tuple to the dictionary */
}
public virtual void Save()
{
delegate d = dict[t.GetType().FullName];
d.Item1(this);
}
}
class ChildClass : BaseClass<ChildClass>
{
[SomeCustomAttribute]
public int SomeID {get;set;}
[SomeCustomAttribute]
public string SomeName {get; set;}
}
public class Program
{
public static void Main(string[] args)
{
ChildClass c = new ChildClass();
c.Save();
}
}
Obviously the above code won't compile. I'll restate : I want the child class to pass itself as the generic parameter and not any other child of BaseClass.
(The above code is kind of a psuedo code and will still not compile).
You can do this:
public class BaseClass<T> where T: BaseClass<T> { }
public class ChildClass : BaseClass<ChildClass> { }
But this doesn't force you to use ChildClass as the generic parameter. You could do this public class OtherChildClass : BaseClass<ChildClass> { } which would break the "coontract" that you want to enforce.
The direct answer is that if your accessing a static method then typeof(T) will give you the type for reflection.
However, there is probably better solutions than using reflection. Options:
1) Static constructor on the child class.
2) Abstract method declared in the base class.
I do not know the application, but I get concerned about my design if I feel like using a static constructor, I also get concerned if a base class needs to initialize the child class.
I suggest looking at injection as a solution rather than inheritance. It offers superior unit testing and often a better architecture.
More info (after initial post), this is my preferred solution:
public interface IRegesterable
{
void Register();
}
public class Widget : IRegesterable
{
public void Register()
{
// do stuff
}
}
public class Class1
{
public Class1(IRegesterable widget)
{
widget.Register();
}
}
Hope this helps
The ConcurrentDictionary is being used as a Set<Type>. We can check in the Set<Type> if the type has been initialized. If not we run RegisterType on the type.
public abstract class BaseClass
{
//Concurrent Set does not exist.
private static ConcurrentDictionary<Type, bool> _registeredTypes
= new ConcurrentDictionary<Type, bool>();
protected BaseClass()
{
_registeredTypes.GetOrAdd(GetType(), RegisterType);
}
private static bool RegisterType(Type type)
{
//some code that will perform one time processing using reflections
//dummy return value
return true;
}
}
public class ChildClass : BaseClass
{
}
There are several inefficiencies with this pattern though.
object.GetType() is pretty darn slow, and inefficient.
Even with the HashSet behavior, we are checking for initialization on each instanciation. Its as fast as I can get it, but its still pretty superfluous.

Setting Custom Values on Extended class

Im not sure if it is possible. I am running into a unique issue dealing with a clients api.
I am needing to extend a class and add a bool property that does not exist in the base class.
below is an example of what I am trying to accomplish.
public class baseClass
{
//.. No Editable Access
}
public class Extended
{
public bool flaggedAsDeleted(this baseClass bc)
{
//Idealy was looking for get; set; but I know that don't work
return true;// Need to know if possible to set property on baseClass or Alternative
}
public void flagAsDeleted(this baseClass bc)
{
flaggedAsDeleted = true;
}
}
public class program
{
public void doit()
{
baseClass bc = new baseClass();
bc.flagAsDeleted();
}
}
If you're trying to actually extend a class, you do it like this:
public class BaseClass
{
//.. No Editable Access
}
public class Extended : BaseClass
{
public bool FlaggedAsDeleted { get; set; }
}
If you're trying to add data to an existing class, you have two options:
Inheritance - as seen above.
Encapsulation - create a new object that holds an instance of the type you're adding to.
C# provides a feature called Extension Methods, which allows you to seemingly add methods to existing classes. However, these are really just syntactic sugar, as you're still constrained to the class's public API.
public class BaseClass
{
public int Value { get; set; }
}
public static class ExtensionMethods
{
public static void Increment(this BaseClass b)
{
b.Value += 1;
}
}
Extension methods do not allow you to add data to an existing class though.
This is not unique. This is a common problem solved using a Design Pattern called decorator.

Categories

Resources