How to avoid downcast in derived class - c#

I have parent class (Base) and child class (Derived). Then another interface use Base as the Generic Type and within that interface call IsDataEqual on derived objects.
That interface receives many implementations of this derived object since it use generic with type constraint to Base.
public interface IMyLogic<T> where T : Base
Everything works fine but I feel bad about having this downcast. Is there anyway to avoid it ?
public abstract class Base
{
public abstract bool IsDataEqual(Base data);
}
public class Derived : Base
{
public string x;
public string Y;
public override bool IsDataEqual(Base data)
{
if(data.GetType() != typeof(Derived))
{
//Type mismatch
throw new Exception();
}
Derived derriveData = data as Derived; //downcast
if (this.x == derriveData.x || this.y == derriveData.y)
{
return true;
}
else
{
return false;
}
}
}
p.s. I can not move x and y to base class due to business logic.

For me, I will use IEquatable<T> to replace your IsDataEqual. I'm not sure could you change your base class or not but these is for your reference
public abstract class Base : IEquatable<Base>
{
public bool Equals(Base? other)
{
throw new NotImplementedException();
}
}
public class Derived : Base, IEquatable<Derived>
{
public string x;
public string Y;
public bool Equals(Derived? obj)
{
throw new NotImplementedException();
}
}

This kind of comparison suggest value type semantics, so I would suggest using records to get value-based comparison out-of-the-box (requires c#9 or higher).
Unfortunately, though, we don't have a generic constraint for records for you to use in your interface (that would look like public interface IMyLogic<T> where T : record), but since records can only inherit from other records (see here), it's enough to simply change your base type to a record (you won't need the IsDataEqual() abstract method anymore, but I'm assuming that's not the only reason for you to have a base class)

Related

Implementing a generic interface for any type in a concrete class in C#

I want to do something like the following
public abstract class StaticValue : IRefDynamicValue<RefT>
{
public abstract int get();
public int get(RefT refValue)
{
return get();
}
}
public interface IRefDynamicValue<RefT>
{
public int get(RefT refValue);
}
In my specific case, I'm making a game where I have IRefDynamicValue<Actor>, IRefDynamicValue<Ability>, etc., but I want StaticValue (basically just an int) to be able to serve as any of them (for example an ability parameter).
In general though, the situation is that I have a concrete type that I want to be able to implement a generic interface for any type because it just ignores and never uses the type parameter.
The code above of course isn't possible in C#. Is there a different way to implement this kind of relationship in C#, either through some other trick with generics or just an alternate code structure?
Implement IRefDynamicValue<object>, and make IRefDynamicValue contravariant:
public abstract class StaticValue : IRefDynamicValue<object>
// and also:
public interface IRefDynamicValue<in RefT>
Now you can do:
IRefDynamicValue<Actor> x = someStaticValue;
Note that this doesn't work for RefTs that are value types.
It seems to me that you need this:
public abstract class StaticValue : IRefDynamicValue
{
public abstract int get();
public int get<RefT>(RefT refValue)
{
return get();
}
}
public interface IRefDynamicValue
{
public int get<RefT>(RefT refValue);
}

How to enforce a derived type for a method that is implemented from abstract?

My abstract class has a method that is abstract like this:
public abstract void Run(BaseType baseType);
And now in my derived class which has to implement this function, i want it to only accept a specific derived type from BaseType
So it would have:
public override void Run(DerivedType derivedType){}
Is there any way to enforce this at all ?
Currently i have to do:
public override void Run(BaseType baseType) {
if(!(baseType is DerivedType)) {
// throw exception
}
}
It's not very strict with enforcing the type - i was wondering if there is a way to do so without the need to constantly add a type check ?
I've sometimes used this pattern:
public interface IHandler
{
void Run();
}
public abstract class BaseHandler<TObj> : IHandler
where TObj: BaseType
{
protected readonly TObj _obj {get;set;}
public BaseHandler(TObj obj)
{
this._obj = obj;
}
public abstract void Run();
}
public class DerivedHandler : BaseHandler<DerivedType>
{
public DerivedHandler(DerivedType obj) : base(obj)
{
}
public override void Run()
{
// do stuff with base._obj
}
}
public class HandlerService
{
public IHandler CreateHandler<TObj>(TObj obj)
{
// Depending on your DI container, you could resolve this automatically from the container
if (typeof(TObj) == typeof(DerivedType))
{
return new DerivedHandler(obj);
}
throw new NotImplementedException();
}
}
This allows you to define a specific "handler" for each derived type, and then access it through a common interface.
The idea is that you instantiate a specific handler for the object, and then methods like Run() operate on that object. You can then resolve a handler through the service.
I'll fill in some more info later when I have time.
You want the language to do something that it really shouldn't. You want a covariant argument, which violates the Liskov Substitution Principle: It makes the implementation of the abstract class not usable in every situation where the abstract base class is usable. This is the whole point of abstract base classes to begin with.
Although it could make sense to have a covariant return type (returning a more derived type then the abstract methods specifies) the language also prevents you to do that.

Add an extra method in only one of the many subclasses of an abstract class

I have an abstract class but and 6 different implementations of it. Now for one of them I would like to add an extra public method but would not like to add it to the abstract class because the other 5 implementations don't need it.
Is there a way of implementing this? I am getting an error when I add this new method without it being in the abstract class.
Here is the code:
namespace Results.Parser
{
public abstract class Parser<T> where T: ReportItem
{
public abstract string GetNodeName();
public abstract IEnumerable<ReportItem> ParseXml(TextReader stream);
public abstract List<ReportItem> SumValueOfDuplicateRows(List<T> reportList);
public virtual bool MeetsCriteria(ReportItem reportItem)
{
return reportItem.Value.SafeConvertToDecimal() != 0;
}
}
}
public class ElementParser : Parser<ReportItem>
{
public override string GetNodeName()
{
return "Element";
}
public override List<ReportItem> SumRiskValueOfDuplicateRows(List<ReportItem> reportList)
{
// do something
}
public void SerializeXml(TextReader stream)
{
//new method which is not in abstract class
}
public override IEnumerable<ReportItem> ParseXml(TextReader stream)
{
//do something
}
}
namespace Results.Producer
{
public class RepositoryManager
{
private void GetResponse(TextReader stream)
{
var parser = new ElementParser();
parser.SerializeXml(stream);
}
}
I am getting an error when I add this new method without it being in the abstract class.
A superclass reference to a subclass instance can't access methods not defined in the super class. You will need to explicitly cast your reference to a subclass reference type to be able to access the extra method from the subclass.
Let A be the abstract class and let B be the class where you have an extra method called extra. Let a be a reference of type A to an instance of type B. To access the extra method in B, do this :
((B)a).extra();
That being said, if only one of the classes needs additional behavior that is different, you should consider using composition over inheritance. See this answer that explains the famous duck problem that is similar to the situtation you are in currently

Generics Inheritance and field declaration (class<T> where T : class<T>)

I have the following class definition:
public abstract class BaseExample<T> where T : BaseExample<T>
{
public abstract T Clone(T original);
}
and its inheritances
public class Example01 : BaseExample<Example01>
{
public override Example01 Clone(Example01 original)
{
return this; // not the actual implementation
}
}
public class Example02 : BaseExample<Example02>
{
public override Example02 Clone(Example02 original)
{
return this; // not the actual implementation
}
}
How to declare a variable with the type or the base class? Since the following declaration doesn't compile:
private BaseExample<T> declarationA;
private BaseExample<T> declarationA;
private BaseExample declarationB;
It won't work as whatever you assign to generic type T cannot really ever be BaseExample<T>.
BaseExample<int> declarationA;
in case above int can't really be BaseExample<int> (int != BaseExample<int>)
I need to have a instance of BaseExample that could receive both Example01 or Example02 values. e.g.: BaseExample a = new Example01()
You can't - BaseExample<Example01> and BaseExample<Example02> are different types. There's not a base type (other than object) that could hold either type.
Suppose you could:
BaseExample a = new Example01();
what would the return type of a.Clone() return?
If your code is within a generic class ot method, then you could:
public T MyMethod<T>(T value) where T : BaseExample<T>
{
BaseExample<T> a = value;
return value.Close();
}
But you'd then have to specify the type when calling the method, e.g.
Example01 a1 = new Example01();
Example01 a2 = MyMethod(a1); // MyMethod<Example01> is inferred by the compiler
As mentioned, because Generic<T1> and Generic<T2> are different classes, you cannot assign them to the same variable.
One way I get around this is to use a non-generic base class, such that
public abstract class BaseExample { ... }
public abstract class BaseExmmple<T> : BaseExample
where T : BaseExample<T>
{ ... }
This can be made more safe by implementing an internal abstract member, such that outside classes cannot implement BaseExample.
If you wish to be able to call .Clone() from an object held in a variable of the non-generic type, you should implement an object-returning form which is wrapped by the generic class to call the generic form.

Use derived type in base abstract class

Ok, I have a number of different classes deriving from a base class.
This base class is an abstract containing commom methods.
One of the methods is a Copy method, wich should be present in all derived classes, so, I've put it in the base class.
BUT, I want it to return the derived type not the base nor object.
The solution I got for that, is using a type paramter:
abstract class CopyableClass<T>
{
public abstract T Copy();
}
class DerivedClass : CopyableClass<DerivedClass>
{
public override DerivedClass Copy()
{
//do what is needed for copy and return a new DerivedClass
}
}
So, the main purpose here is to
Remove the type parameter in the base class and still make the method return the corresponding derived type.
One workaround.
The best thing I could do so far is one of the comments below, but it still uses a generic parameter
abstract class BaseClass
{
//base methods not related to deriving type
}
interface ICopyable<T>
{
T Copy();
}
class DerivedClass : BaseClass, ICopyable<DerivedClass>
{
public DerivedClass Copy()
{
//do what is needed for copy and return a new DerivedClass
}
}
You can't really. The base class can't possibly know all the future implementations. You'll have to resort to a generic abstract class (like you did) type or a generic Copy method.
public abstract class CopyableClass
{
public abstract T Copy<T>() where T : CopyableClass;
}
public class DerivedClass : CopyableClass
{
public override T Copy<T>()
{
if(typeof(T) != typeof(DerivedClass))
throw new ArgumentException();
// return your copy
}
}
Or, if you want to generalize the type check in your base class:
public abstract class CopyableClass
{
public T Copy<T>() where T : CopyableClass
{
if(GetType() != typeof(T))
throw new ArgumentException();
return (T) Copy();
}
protected abstract CopyableClass Copy();
}
public class DerivedClass : CopyableClass
{
protected override CopyableClass Copy()
{
return // Your copy;
}
}
Note that the second method puts alot of trust into the implementation of the derived class as it'll blindly cast the return value of the abstracted method. The compiler will let you return another type, implementing CopyableClass, in a derived type but it will be a runtime error. This is not a problem if you have the absolute control over all of the derived implementations (ie your abstract class also have an internal constructor).
This solution involves a middle class but I think its more inline with what the you are looking for. At least you get the possible benefit of isolating your copy code
public abstract class BaseClass
{
}
public abstract class CopyableClass<T> : BaseClass
where T: BaseClass, new()
{
public T Copy()
{
var copy = new T(); // Creating a new instance as proof of concept
return copy;
}
}
public class DerivedClass : CopyableClass<DerivedClass>
{
}
You actually want to implement copy in the base class and have it return T. This will make is so you call it with a type argument and it returns that type.
public static T Copy<T>() where T : CopyableClass
{
T retVal = new T();
// do whatever copying is required
return retVal;
}
To call it you do;
DerivedClass d = Copy<DerivedClass>();
Your code to actually do the copy might be a bit more work to make generic but it's worth the effort given you will have a single implementation of Copy() that works for any derived type. I don't know what logic belongs in the method so I've just stubbed things out. Also, I'd recommend checking out generics in general. They're often the best option for things like this. If your implementations need to be unique to the base class' keep the same method definition but make it abstract and then override it in the base classes.
This will allow you to case this base class to the derived type and return it.
public abstract class BaseClass<TDerived> : where TDerived: BaseClass<TDerived>
{
public TDerived DoSomethingCommon(string param)
{
var derivedType = (TElement)this;
//do something.
return derivedType;
}
}

Categories