0

I am extending my C# J2K library to dynamically register codecs from other assemblies. That part is working, but I am having trouble understanding IsAssignableFrom(TypeInfo) and how I can deduce which class instance to handle a given type (SKBitmap, Image, etc).

So far this is what I have come up with. I have an interface named IImageCreator and all codecs are instantiated into

static readonly List<IImageCreator> _creators

I then have an abstract base class that implements IImageCreator like so:

abstract class ImageCreator<TBase> : IImageCreator

The codecs are then implemented into sealed classes like so:

sealed class SKBitmapImageCreator : ImageCreator<SKBitmap> {...}
sealed class WindowsBitmapImageCreator : ImageCreator<Image> {...}

etc.

I have a static method for encoding an image:

static BlkImgDataSrc ToPortableImageSource(object imageObject)
{
    _creators.Single(c => c.GetType().GetTypeInfo().IsAssignableFrom(imageObject.GetType().GetTypeInfo()));

This is where I am getting hung up as it throws an exception Sequence contains no matching element

Note that imageObject will be of a handled type such as SKBitmap

I was under the impression that this would deduce the proper instance to handle the imageObject based on the documentation:

Returns true if any of the following conditions is true:
(...)
c is a generic type parameter, and the current instance represents one of the constraints of c.

Where have I gone astray? How can I deduce the proper instance to handle the object?

1 Answer 1

3

The imageObject is not of type IImageCreator, it's of some TBase image type.

So you need to construct a dynamic ImageCreator<TBase> TypeInfo to compare to.

var type = typeof(ImageCreator<>).MakeGenericType(imageObject.GetType());
var creator = _creators.SingleOrDefault(c =>
    c.GetType().IsAssignableFrom(type))
    ?? throw new Exception($"Image type {imageObject.GetType()} not supported");

However, a much better way of doing it would be to have a ImageType property on your base interface:

public interface IImageCreator
{
    Type ImageType { get; }
}

Then the abstract generic class implements it:

abstract class ImageCreator<TBase> : IImageCreator
{
    public Type ImageType => typeof(TBase);
}

And then you can simply do:

var creator = _creators.SingleOrDefault(c =>
    c.ImageType.IsAssignableFrom(imageObject.GetType()))
    ?? throw new Exception($"Image type {imageObject.GetType()} not supported");
Sign up to request clarification or add additional context in comments.

3 Comments

Or just build a Dictionary<Type, IImageCreator> once, so you don't have to search the list at runtime...
Doesn't work for IsAssignableFrom, only for exact match. You'd need to loop through all base classes and interfaces to find the first match.
Which is more efficient would depend on how many IImageCreator types you have. And if the image types are sealed. Once you find a match, you can then add it to the dictionary for next time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.