Excluding Some Properties During Serialization Without Changing the Original Class

C#: cast to generic interface with base type

Maybe it helps you if I explain why this cast is forbidden: Assume that you have the following function

void myFunc(IValidator<BaseEntity> myValidator) {
myValidator.IsValid(new BaseEntity());
}

This code would compile correctly. Nevertheless, if you passed an OrderValidator to this function, you would get a run-time exception, because OrderValidator.IsValid expects an Order, not a BaseEntity. Type safety would no longer be maintained if your cast were allowed.

EDIT: C# 4 allows for generic co- and contravariance, but this would not help in your case, since you use T as an input parameter. Thus, only casting to an IValidator<SomeSubtypeOfOrder> could be done in a type-safe way.

So, to be clear, you cannot cast OrderValidator to IValidator<BaseEntity> because your OrderValidator can only validate orders, not all kinds of BaseEntities. This, however, is what would be expected of an IValidator<BaseEntity>.

Cast GenericDerived to GenericBase

You cannot cast a Generic<Derived> to a Generic<Base>.

Just imagine if you could. You have a List<Wolf> and cast it to a List<Animal>. Now you could .Add() a Sheep to your List<Animal>. But wait... now your List<Wolf> contains a Sheep. What a mess.

This would only work out if you could make sure that the thing you cast to is read-only in all possible forms. This is was co- and contravariance is all about. It only works for interfaces though.

Casting an object to a generic interface

If I understand the question, then the most common approach would be to declare a non-generic base-interface, i.e.

internal interface IRelativeTo
{
object getRelativeTo(); // or maybe something else non-generic
void setRelativeTo(object relativeTo);
}
internal interface IRelativeTo<T> : IRelativeTo
where T : IObject
{
new T getRelativeTo();
new void setRelativeTo(T relativeTo);
}

Another option is for you to code largely in generics... i.e. you have methods like

void DoSomething<T>() where T : IObject
{
IRelativeTo<IObject> foo = // etc
}

If the IRelativeTo<T> is an argument to DoSomething(), then usually you don't need to specify the generic type argument yourself - the compiler will infer it - i.e.

DoSomething(foo);

rather than

DoSomething<SomeType>(foo);

There are benefits to both approaches.

Cast to generic type in C#

Does this work for you?

interface IMessage
{
void Process(object source);
}

class LoginMessage : IMessage
{
public void Process(object source)
{
}
}

abstract class MessageProcessor
{
public abstract void ProcessMessage(object source, object type);
}

class MessageProcessor<T> : MessageProcessor where T: IMessage
{
public override void ProcessMessage(object source, object o)
{
if (!(o is T)) {
throw new NotImplementedException();
}
ProcessMessage(source, (T)o);
}

public void ProcessMessage(object source, T type)
{
type.Process(source);
}
}

class Program
{
static void Main(string[] args)
{
Dictionary<Type, MessageProcessor> messageProcessors = new Dictionary<Type, MessageProcessor>();
messageProcessors.Add(typeof(string), new MessageProcessor<LoginMessage>());
LoginMessage message = new LoginMessage();
Type key = message.GetType();
MessageProcessor processor = messageProcessors[key];
object source = null;
processor.ProcessMessage(source, message);
}
}

This gives you the correct object. The only thing I am not sure about is whether it is enough in your case to have it as an abstract MessageProcessor.

Edit: I added an IMessage interface. The actual processing code should now become part of the different message classes that should all implement this interface.

C# Convert generic, inherited type with interface to base type with same interface

Alright, step by step.

iPoppable<Lion> lions = new Group<Lion>();

Works, because Group implements iPoppable and generic parameter T is the same.

iPoppable<Animal> animals = lions;

Works, because both of them are iPoppable and Lion derives from Animal. More formally, this is an example of covariance.

An object that is instantiated with a more derived type argument is assigned to an object instantiated with a less derived type argument. Assignment compatibility is preserved.

by Microsoft Docs.

Group<Lion> lions2 = lions;

Does not work, because you assign an interface type to a class type. iPoppable just says that lions has Lion Pop(); method, no more! By saying Group<Lion> lions2 = lions; you claim that lions2 is a full-featured Group object which will have all methods and properties of Group class. Which is not necessarily true, and that's why compiler complains.

You may help compiler by saying

Group<Lion> lions2 = (Group<Lion>)lions;

because you know for a fact that particularly lions, although the type is iPoppable is in fact Group.

To illustrate what the compiler is afraid of, see the following snippet.

interface iPoppable<out T>
{
T Pop();
}
interface iPushable<in T>
{
void Push(T ag_t);
}

class Program
{
static void Main()
{
// Here, we know the truth, so we cast
iPoppable<bool> group = new Group<bool>();
Group<bool> group2 = (Group<bool>)group; // Possible

// What about here? We also convert iPoppable to Group...
iPoppable<bool> notGroup = new NotGroup<bool>();
Group<bool> notGroup2 = (Group<bool>)notGroup; // Bad... Compiler was right...

notGroup2.HelloGroup = true; // HA! Runtime exception.
// That's what compiler was worrying about.

// System.InvalidCastException: Unable to cast object of
// type 'NotGroup`1[System.Boolean]' to type 'Group`1[System.Boolean]
}
}

class Group<T> : iPoppable<T>, iPushable<T>
{
public void Push(T ag_t) { }
public T Pop() { return default(T); }

public bool HelloGroup { get; set; }
}

class NotGroup<T> : iPoppable<T>, iPushable<T>
{
public void Push(T ag_t) { }
public T Pop() { return default(T); }

public bool HelloNotGroup { get; set; }
}

Generic type is cast to base class

The type parameter T is inferred at compile time, that's why it's different when you call a method with a parameter Base b1 and Derived b2 (using var simply makes the type of the variable the same as the type of the expression used to initialize it).

The simplest way to make it happen at run time is to cast the parameter to dynamic

SomeMethod((dynamic)b1);

This will basically run the compiler at run time and perform overload resolution and type inference with run time types instead of compile time types.

In general what you're asking about is called double dispatch - choosing the method to call based on both the runtime type of the object whose method you call, and the run time type of the parameter. A traditional way to achieve it is to use the visitor pattern.

C# : Downcasting Generic object with derived interfaces to the base interface

Your list is List<IAlarmItem<IConfigAlarmBase>> and you try to add an AlarmItemRangedBase<IConfigAlarmRanged>, so you have type mismatch even if IConfigAlarmRanged inherits from IConfigAlarmBase because IAlarmItem<IConfigAlarmBase> and IAlarmItem<IConfigAlarmRanged> are not the same type : they are two distinct closed constructed generic types and you can't cast from one to the other.

For example, List<string> and List<int> are distinct types, there is no hierarchy between and no side-casting is available.

Generics -Open and closed constructed Types

About the lack of true generic polymorphism and the missing diamond operator in C#

Unable to cast object of generic type to generic interface C#

That's a lot of levels of indirection you got there...

Here's the issue:

public abstract class Rule<TDmModel, TMiddle, TDb> : IRule<TDmModel, TDb>
where TDmModel : IDmModel
where TDb : IDbModel

public class RuleA : Rule<DmModel, Middle, DbMode>
public class RuleB : RuleA
...
var ruleB = (IRule<IDmModel, IDbModel>)new RuleB();

RuleB implements IRule<DmModel, DbMode>

This cannot be cast to IRule<IDmModel, IDbModel>. C# does not support this type of casting. For the same reason, you cannot do List<object> b = (List<object>)new List<string>(); (Gives "Cannot convert type 'System.Collections.Generic.List<string> to System.Collections.Generic.List<object>.")

This is an issue with covariance.

Here is some more information from Microsoft on the subject: https://learn.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance



Related Topics



Leave a reply



Submit