Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to typecast a variable to satisfy multiple type constraints?

I'm trying to replace some existing code that directly references a base class with a generic implementation, for use in other areas. I'm running into an issue where the input objects may have additional interfaces that change behavior.

public interface IExample { }
public interface ISub1 { }
public interface ISub2 { }
public interface ICombined : IExample, ISub1 { }

public class TestGeneric<TBase> where TBase : class, IExample
{
    public void Example<T>(T obj) where T : class, TBase
    {
        if (obj is ISub1 o1)
        {
            //The object must implement both IExample and ISub1 to enter this block
            //Function(o1);   //o1 does not implement IExample
            //Function(obj);  //obj does not implement ISub1
        }
        if (obj is ISub2 o2)
        {
            //The object must implement both IExample and ISub2 to enter this block
            WorkingFunction(obj, o2);
        }
        if (obj is ICombined c)
        {
            //This works if the function is `Example<T> where T: IExample`, but not `Example<T> where T: TBase where TBase: IExample`
            //Function(c);
        }
    }

    private void Function<T>(T obj) where T : class, TBase, ISub1
    {
        //Do stuff
    }

    private void WorkingFunction<T1, T2>(T1 asExample, T2 asSub)
        where T1 : class, TBase
        where T2 : class, ISub2
    {
        //Do stuff - asExample and asSub are the same object, but implement different interfaces
    }
}

The objects passed to Example always implement IExample, and may implement ISub1 or ISub2. If so, other logic is needed and it calls another function that uses more specific type constraints. This is just a routing function so the caller doesn't need to check the interfaces. The caller only knows that it has an IExample - these objects come from XML deserialization and the actual class is based off the contents of the XML.

The issue is that the cast to check if the object is an ISub1 gives a variable that's just typed as ISub1, not also IExample. The code block will only be entered if the object implements both interfaces, but I can't find a way to tell the compiler that. With the existing concrete implementation, I can just make a new interface that implements both IExample and ISub1 (ICombined) and cast to that. Is there a way to do anything similar with a generics? Either declare an interface that extends a generic type parameter, or a "double type cast" to both IExample and ISub1?

As a workaround I can pass in two separate parameters to the function, one as IExample the second as ISub1. This seems to work, but it's rather hackish.

Is there a way to tell the compiler that the objects satisfies both the generic type parameter and another interface so I can pass it on to another function?

like image 925
DylanStreb Avatar asked Oct 31 '25 13:10

DylanStreb


1 Answers

I found concise solution (which then I also saw was suggested by shingo in comments).

Based on Using type dynamic:

The dynamic type is a static type, but an object of type dynamic bypasses static type checking

We could use just

if (obj is ISub1)
{
    Function((dynamic)obj);
}

However this will defer type constraints to the runtime. So you have to make sure your implementation is bullet proof.

like image 178
Michał Turczyn Avatar answered Nov 03 '25 04:11

Michał Turczyn



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!