简体   繁体   中英

Func with generic class parameter and casting

I have Func<> that have generic class as input parameter. The question is how to cast it to similar Func but with class that have parameter derived from previous? For now below code give me null in fu2.

var fu = new Func<Envelope<Base>, object>(Simple);
var fu2 = fu as Func<Envelope<Derived>, object>;

public class Envelope<T>
{
    public T Enveloped { get; set; }
}
public class Base
{

}
public class Derived: Base
{

}

Func<T, object> is contravariant in T so

var fu2 = fu as Func<Envelope<Derived>, object>;

will succeed if Envelope<Derived> is a subtype of Envelope<Base> . Classes are invariant but you can define an interface:

public interface IEnvelope<out T>
{
    T Enveloped { get; }
}

and have Envelope<T> implement it. Then the following will compile:

Func<IEnvelope<Base>, object> fu = null;
Func<IEnvelope<Derived>, object> fu2 = fu;

Casting a generic expression does not work, because there is no covariance among lambda expressions.

However, you can make an expression that constructs a new Envelope<Base> , and wraps the enveloped derived object into it, like this:

var fu = new Func<Envelope<Base>,object>(Simple);
Func<Envelope<Derived>,object> fu2 = x => fu(new Envelope<Base> {Enveloped = x.Enveloped});

The new expression calls fu with new Envelope<Base> {Enveloped = x.Enveloped} parameter, which is an envelope of a compatible type constructed from the parameter of the fu2 expression.

Demo.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM