Consider the following classes:
public class X {};
public class Y : X {};
public class Z : X {};
public class A {
public bool foo (X bar) {
return false;
}
};
public class B : A {
public bool foo (Y bar) {
return true;
}
};
public class C : A {
public bool foo (Z bar) {
return true;
}
};
Is there a way to achieve the following desired output?
A obj1 = new B();
A obj2 = new C();
obj1.foo(new Y()); // This should run class B's implementation and return true
obj1.foo(new Z()); // This should default to class A's implementation and return false
obj2.foo(new Y()); // This should default to class A's implementation and return false
obj2.foo(new Z()); // This should run class C's implementation and return true
The issue I am having is that class A's implementation is always being called regardless of the arguments passed.
You need to make the foo method in class A virtual so it can be overridden properly and called polymorphically.
public class A { public virtual bool Foo (X bar) { ... } }
public class B { public override bool Foo (X bar) { ... } }
The way you are doing it at the moment, is effectively defining a new method implementation in B and C which will only be called if the instance is of that type. Since you are declaring them as type A (A obj1 = new B();) and the method is not virtual then the A implementation will always be called.
I believe you desire to define virtual method and override it with a signature that contains derived types. That is not possible as the method that overrides the base one should have the same signature. Probably this is because that would require the compiler to apply complex traversal rules. So as suggested in the previous answer to get the desired behavior:
public class A { public virtual bool Foo (X bar) { ... } }
public class B {
public override bool Foo (X bar) {
if(bar is Y) { ... }
else base.Foo(bar);
}
}
Related
Considering the classes below, I would like to be able to write:
B b = new B();
b.f(1); // calls b._a.f(int)
b.f("howdy!"); // calls b._a.f(string)
Class A cannot be modified.
public class A
{
public void f(int i) { }
public void f(string s) { }
}
public class B
{
public void f<T>(T v)
{
_a.f(v); // fails
}
A _a = new A();
}
If you really want to simplify your f pass-through down to a single method, you'll have to use run-time type checking. I don't see any other way around it. Generics aren't going to work here.
public void f(object v)
{
if (v is int i)
_a.f(i);
else if (v is string s)
_a.f(s);
else
throw new InvalidOperationException();
}
I gather that you are hesitant to just expose _a because there are some methods on it that you would rather not be accessible to the caller? Could you introduce an interface, or would that be considered a modification to class A?
public interface IFoo
{
void f(int i);
void f(string s);
}
public class A : IFoo
{
...
}
public class B
{
public IFoo A => _a;
}
I want objects deriving certain class A to also somehow derive the implementation of the Equals(A other) that would do the following: if types of this and other are different, return false, otherwise return this.value == other.value.
My attempt looks like this:
public class A<T> : IEquatable<A<T>>
where T: A<T>
{
protected string Value { get; }
public A(string value)
{
Value = value;
}
public bool Equals(A<T> other)
{
var concrete = other as T;
if (concrete == null)
{
return false;
}
return concrete.Value == Value;
}
}
public class B : A<B>
{
public B(string value)
: base(value)
{
}
}
public class C : A<C>
{
public C(string value)
: base(value)
{
}
}
class Program
{
static void Main(string[] args)
{
var b1 = new B("val");
var b2 = new B("val");
var c = new C("val");
Console.WriteLine(b1.Equals(b1));
Console.WriteLine(b1.Equals(b2));
Console.WriteLine(b2.Equals(b1));
Console.WriteLine(b1.Equals(c));
Console.WriteLine(b2.Equals(c));
Console.WriteLine(c.Equals(b1));
Console.WriteLine(c.Equals(b2));
}
}
This works fine until we derive more:
public class D : C
{
public D(string value)
: base(value)
{
}
}
then it breaks:
var d = new D("val");
Console.WriteLine(d.Equals(c)); // prints "True"
and now I am stuck. How do I make it work?
Both fixing the implementation to work with more than one level of inheritance and preventing more than one level of inheritance are acceptable.
I understand though that I just have to declare all first level descendants of A<T> as sealed, but that's the last resort unless it can be somehow enforced (so non-sealed descendants of A<T> would cause compilation error).
Or maybe my approach is wrong completely?
This is all because the as operator can convert subclasses to superclasses without problems.
What you want to do is to check the types and see whether they are equal:
if (this.GetType() == other.GetType()) {
return false;
}
This question is kind of related, about the behaviours of GetType, typeof and is, which works similar to as.
Given the following types and snippet:
interface IFoo<out T> {
T doThing();
}
class Bar : IFoo<int> {
int doThing() => 0;
}
var list = new List<IFoo<object>> {
new Bar() //fails to compile
};
I understand that it's not possible to add a Bar to a List<IFoo<object>>, because Bar's T is a value type.
Given that I need to IFoo type-safe, how can I change Bar or the collection so that it's possible to store both IFoo<T> for some value and reference types?
Basically I see only one option here:
public interface IFoo<out T>:IFoo
{
T doThing();
}
public interface IFoo
{
object doThing();
}
public class Bar : IFoo<int>
{
public int doThing(){return 0;}
object IFoo.doThing()
{
return doThing();
}
}
var list = new List<IFoo>
{
new Bar()
};
I have an abstract class A and a abstract method with a parameter which is again abstract class B defined in the same abstract class A. When I extended this abstract class A as apart of another class C how can I implement the method with parameter of nested abstract class.
public abstract class A<T, V>
{
public abstract int GetObject(T t, V v);
public abstract int GetAnotherObject(B b);
public abstract class B{}
}
This class is extended by another class C
public class C: A<ABC, DEF>
{
public C()
{
}
public override int GetObject(ABC abc, DEF def)
{
return 10;
}
public override int GetAnotherObject(B b)
{
return 15;
}
}
How to implement class B with some properties and pass in GetAnotherObject method. Could someone please help me.
From ECMA:
Any class nested inside a generic
class declaration or a generic struct
declaration (ยง25.2) is itself a
generic class declaration, since type
parameters for the containing type
shall be supplied to create a
constructed type.
So, you cannot implement nested B without providing type arguments for A.
void Main()
{
var c = new C();
var result = c.GetAnotherObject(new BImpl<string, int>());
}
public class BImpl<T, V> : A<T, V>.B
{
public override int BM()
{
return 1;
}
}
// Or you can supply type arguments right here
//public class BImpl : A<string, int>.B
//{
// public override int BM()
// {
// return 1;
// }
//}
public abstract class A<T, V>
{
public abstract int GetObject(T t, V v);
public abstract int GetAnotherObject(B b);
public abstract class B
{
public abstract int BM();
}
}
public class C : A<string, int>
{
public C()
{
}
public override int GetObject(string abc, int def)
{
return 10;
}
public override int GetAnotherObject(B b)
{
return b.BM();
}
}
You're very close already.
public class C<ABC, DEF> : A<ABC, DEF>
{
public C()
{
}
public override int GetObject(ABC abc, DEF def)
{
return 10;
}
// since B is a nested class of A, it has no scope outside of A
// outside of the definition of A, it must always be referred to as A.B
public override int GetAnotherObject(A<ABC,DEF>.B b)
{
return 15;
}
}
public class D : A<ABC,DEF>.B
{
// implementation of A.B
}
Keep in mind that C will always take exactly A.B. You will never be able to define an implementation of A.B (let's call it D) and have C's method signature refer to that in the override. GetAnotherObject is defined in A as taking an A.B and must therefore be implemented to accept any A.B, not some specific implementation of A.B.
RE: your comment on how to implement A.B inside C
There is no point to implementing A.B inside C. C will still have to have A.B in its method signature. But if you really must, for some reason.
public class C<ABC, DEF> : A<ABC, DEF>
{
// C's implementation of A
public override int GetAnotherObject(A<ABC,DEF>.B b)
{
return 15;
}
public class D : A<ABC,DEF>.B
{
// implementation of A.B
}
}
Note that GetAnotherObject still takes an A.B, not a D.
How about
public class C<ABC, DEF> : A<ABC, DEF>
{
public C()
{
}
public override int GetObject(ABC abc, DEF def)
{
return 10;
}
public override int GetAnotherObject(B b)
{
return 15;
}
}
Just postfix the class with the generics.
I have class Foo<T> and an instance method Foo<T>.M with return type T and signature M(Bar bar). There is a constraint on T (T : AbstractBaseClass) so that I'm certain that T has a property T.SomeProperty (and a parameterless constructor constraint). Let's say that M has to set the value of T.SomeProperty based on bar as well on the concrete type of T. I do not want my code to look like
T t = new T();
if(typeof(T) == T1) {
T.SomeProperty = // some function of bar
}
else if(typeof(T) == T2) {
T.SomeProperty = // some function of bar
}
else if(typeof(T) == T3) {
T.SomeProperty == // some function of bar
}
I do not want to put an instance method on T that takes in values from Bar to populate T.SomeProperty because that will make my Ts have a dependency on some things that I do not want it to them a dependency on.
What is my best option here?
Here's what I mean:
class AbstractBaseClass {
public int SomeProperty { get; set; }
}
class Foo<T> where T : AbstractBaseClass, new() {
public T M(Bar bar) {
T t = new T();
t.SomeProperty = // function of bar, typeof(T)
return t;
}
}
How to write M but avoid type-by-type logic on the type parameter T?
Edit:
What about this? This is riffing on Corey's idea:
interface ISomePropertyStrategy<T> {
int GetSomeProperty(Bar bar);
}
class SomePropertyStrategyForConcreteClass1 :
ISomePropertyStrategy<ConcreteClass1> {
public int GetSomeProperty(Bar bar) { return bar.MagicValue + 73; }
}
class SomePropertyStrategyForConcreteClass2 :
ISomePropertyStrategy<ConcreteClass2> {
public int GetSomeProperty(Bar bar) { return bar.MagicValue - 12; }
}
class Foo<T> where T : AbstractBaseClass, new() {
private readonly ISomePropertyStrategy<T> strategy;
public Foo<T>(ISomePropertyStrategy<T> strategy) {
this.stragety = strategy;
}
public T M(Bar bar) {
T t = new T();
t.SomeProperty = this.strategy.GetSomeProperty(bar);
return t;
}
}
The only thing I don't like about this is that it uses a generic interface where the generic type parameter never appears in the interface. I think I once saw a comment from Eric Lippert where he said that wasn't a good idea, but I can't remember. Sorry.
So you have this:
class Foo<T>
where T : AbstractBaseClass, new()
{
T M( Bar bar )
{
T t = new T();
if ( typeof (T) == T1 )
{
t.SomeProperty = bar.SomeMethod();
}
else if ( typeof (T) == T2 )
{
t.SomeProperty = bar.SomeOtherMethod();
}
else if ( typeof (T) == T3 )
{
t.SomeProperty == bar.YetAnotherMethod();
}
}
}
You could do this:
T M( Bar bar, Func<object> barFunction )
{
T t = new T();
t.SomeProperty = barFunction();
}
It doesn't require tight coupling with your Bar method. Here is some information on the Func<T> delegate.
OK, here's a complete program. For the sake of the example, I take Bar to be some class that holds an interesting value (here, 100). I take foo.M to be a routine that wants to add 73 to the number inside Bar if the type argument is ConcreteClass1; it will want to subtract 12 from the number inside Bar if the type argument is ConcreteClass2.
The interface IABCVisitor and the virtual methods AcceptVisitor (one per class) may seem like a lot of overhead, but the nice thing is that you only have to pay that overhead once: once this pattern has been added to your class hiearchy you can reuse it over and over again, whenever your callers want to do custom logic based on type. I hope the program below makes sense to you.
using System;
using System.Diagnostics;
namespace ConsoleApplication33 {
public class Program {
public static void Main() {
var foo1=new Foo<ConcreteClass1>();
var foo2=new Foo<ConcreteClass2>();
var bar=new Bar(100);
var result1=foo1.M(bar);
var result2=foo2.M(bar);
Debug.Print("result1.SomeProperty="+result1.SomeProperty);
Debug.Print("result2.SomeProperty="+result2.SomeProperty);
}
}
//----------------------------------------------------------------------------
// these definitions can appear in project 1
// notice that project 1 does not have any dependencies on Bar
//----------------------------------------------------------------------------
/// <summary>
/// This interface needs a line for each class in the hierarchy
/// </summary>
public interface IABCVisitor<out T> {
T Visit(AbstractBaseClass x);
T Visit(ConcreteClass1 x);
T Visit(ConcreteClass2 x);
}
public abstract class AbstractBaseClass {
public int SomeProperty { get; set; }
/// <summary>
/// All of AbstractBaseClasses' children need to override this property
/// </summary>
public virtual T AcceptVisitor<T>(IABCVisitor<T> visitor) {
return visitor.Visit(this);
}
}
public class ConcreteClass1 : AbstractBaseClass {
public override T AcceptVisitor<T>(IABCVisitor<T> visitor) {
return visitor.Visit(this);
}
}
public class ConcreteClass2 : AbstractBaseClass {
public override T AcceptVisitor<T>(IABCVisitor<T> visitor) {
return visitor.Visit(this);
}
}
//----------------------------------------------------------------------------
// these definitions can appear in project 2
//----------------------------------------------------------------------------
public class Bar {
public int MagicValue { get; private set; }
public Bar(int magicValue) {
MagicValue=magicValue;
}
}
public class Foo<T> where T : AbstractBaseClass, new() {
public T M(Bar bar) {
T t=new T();
t.SomeProperty=t.AcceptVisitor(new CalculateTheRightValue(bar));
return t;
}
}
public class CalculateTheRightValue : IABCVisitor<int> {
private readonly Bar bar;
public CalculateTheRightValue(Bar bar) {
this.bar=bar;
}
public int Visit(AbstractBaseClass x) {
throw new NotImplementedException("not implemented for type "+x.GetType().Name);
}
public int Visit(ConcreteClass1 x) {
return bar.MagicValue+73;
}
public int Visit(ConcreteClass2 x) {
return bar.MagicValue-12;
}
This looks like a pretty classic application of the Visitor Pattern