Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you explicitly cast a variable of type 'object' to satisfy a multi-typed generic constraint?

We have a generic extension method which works only for objects that supports both the INotifyCollectionChanged and IEnumerable interfaces. It's written like this:

public static class SomeExtensions
{
    public static void DoSomething<T>(this T item)
    where T : INotifyCollectionChanged, IEnumerable
    {
        // Do something
    }
}

The following compiles fine since ObservableCollection<string> implements both interfaces and thanks to the 'var' keyword, knownType is strongly typed:

var knownType = new ObservableCollection<string>();
knownType.DoSomething();

However, we are trying to call this from a ValueConverter. The problem is the incoming value is of type object and even though we can test that the passed-in object does implement both interfaces, we can't figure out how to explicitly cast it so we can call that generic extension method. This doesn't work (obviously)...

object unknownType = new ObservableCollection<string>();
((INotifyCollectionChanged,IEnumerable)unknownType).DoSomething();

So how can you cast an object to multiple interfaces so you can call the generic? Not even sure it's possible.

like image 691
Mark A. Donohoe Avatar asked May 11 '15 22:05

Mark A. Donohoe


People also ask

How do you specify a constraint for the type to be used in a generic class?

It will give a compile-time error if you try to instantiate a generic type using a type that is not allowed by the specified constraints. You can specify one or more constraints on the generic type using the where clause after the generic type name.

Which of the following generic constraints restricts the generic type parameter to an object of the class?

Value type constraint If we declare the generic class using the following code then we will get a compile-time error if we try to substitute a reference type for the type parameter.

Which of the following keyword is used to apply constraints on type parameter?

Object, you'll apply constraints to the type parameter. For example, the base class constraint tells the compiler that only objects of this type or derived from this type will be used as type arguments.

Which interface defines methods to control the different generic collections?

NET class library defines several generic interfaces for use with the collection classes in the System. Collections. Generic namespace.


1 Answers

The cleanest way I can think to do this would be dynamic. However, because extension methods don't play nice with dynamic (see blelow), you'll have to reference the extension method explicitly.

Extensions.DoSomething(unknownType as dynamic);

EDIT As a warning aginst the gotcha I ran into here, note that calling the method with explicit dyanmic as the type argument (via DoSomething<dynamic>) will not work - it causes compile errors when trying to match against multiple constraints. In addition, when not using multiple constraints, this results in the dynamic resolving based on the passed variable's compile-time type, not the runtime type.

This will result in a call to Extensions.UnknownType<dynamic>, the dynamic of which will resolve at runtime - meaning it'll use the fully derived type of the given parameter. As long as this parameter implements the desired interfaces, off you go.

Be wary as, like much dynamic code, this could encounter issues that won't be seen until runtime. Use sparingly!

If you make multiple calls with the same generic paremeters, you might be better off adding a generic helper method in your converter and then calling that using value as dynamic

Addendum:

When using dynamic, anything called against the dynamic object will attempt to resolve as a member of the given type at runtime, but will not look up Extension Methods, since they inherently exist in a completely different class, often a different assembly.

like image 166
David Avatar answered Oct 19 '22 23:10

David