C
C#•3y ago
RazorSharpFang

How do you pass into a method a generic after you've reflected? [Answered]

Suppose I suspect that this IEnumerable (non-generic) is also an IReadOnlyList<T> where T : struct. Unfortunately due to the rules of casting, an IReadOnlyList<T> where T : struct is not castable to an IReadOnlyList<object> How unfortunate! But we have reflection! Suppose I have an IEnumerable called source. I can probe its types as follows
// source is of type System.Collections.IEnumerable
var type = source.GetType();
var interfaces = type.GetInterfaces();
for (int i = 0; i < interfaces.Length; i++)
{
var @interface = interfaces[i];
if (@interface is null)
continue;
// null check satisifed
if(@interface.GenericTypeArguments.Length == 1 && @interface.GetGenericTypeDefinition() == typeof(IReadOnlyList<>))
{
// found it. It is in fact an IReadOnlyList<T> where T : struct
// but now what? Can I get a strongly typed reference to an IReadOnlyList<T> where T : struct ?
}
}
// source is of type System.Collections.IEnumerable
var type = source.GetType();
var interfaces = type.GetInterfaces();
for (int i = 0; i < interfaces.Length; i++)
{
var @interface = interfaces[i];
if (@interface is null)
continue;
// null check satisifed
if(@interface.GenericTypeArguments.Length == 1 && @interface.GetGenericTypeDefinition() == typeof(IReadOnlyList<>))
{
// found it. It is in fact an IReadOnlyList<T> where T : struct
// but now what? Can I get a strongly typed reference to an IReadOnlyList<T> where T : struct ?
}
}
Another class takes in as an argument to its constructor, IReadOnlyList<T> Defined below:
public ReadOnlyListWrapper(IReadOnlyList<T> backingList) { /* BODY HERE */ }
public ReadOnlyListWrapper(IReadOnlyList<T> backingList) { /* BODY HERE */ }
How do I after probing call this constructor now that I know it implements the interface as required?
24 Replies
Kai
Kai•3y ago
Is there a reason you need to do this via reflection? I think you can just do
if (source is IReadOnlyList<T> list)
if (source is IReadOnlyList<T> list)
though for that you need a T given somehow. If that's not possible, you can do
var instance = Activator.CreateInstance(typeof(ReadOnlyListWrapper<>).MakeGenericType(@interface.GenericTypeArguments.Single()), source);
var instance = Activator.CreateInstance(typeof(ReadOnlyListWrapper<>).MakeGenericType(@interface.GenericTypeArguments.Single()), source);
But if it's at all possible for you I'd strongly recommend just handing through the generic argument several times, instead of loosing the type somewhere and then restoring it in this way
RazorSharpFang
RazorSharpFangOP•3y ago
I do not have T known.
Kai
Kai•3y ago
In that case the second solution should work. Not very pretty and you loose a bunch of type safety (you also get back an object, so...)
RazorSharpFang
RazorSharpFangOP•3y ago
Oh so I do. Yeah I agree that this isn't pretty, but this is already the backwards-compat slow code-path anyway
Kai
Kai•3y ago
fair enough 😛
RazorSharpFang
RazorSharpFangOP•3y ago
Related to AvaloniaUI PR 8764 if you're interested https://github.com/AvaloniaUI/Avalonia/issues/8764
GitHub
For Avalonia.Controls.ListBox for Items Property, Support for IRead...
Describe the bug For a DataContext View-Model that has Specialized Collections, collections may implement the IList&lt;T&gt; or IReadOnlyList&lt;T&gt; interfaces, neither of which i...
RazorSharpFang
RazorSharpFangOP•3y ago
About collections that don't implement non-generic IList Hence all of the weird casting going on Remember that IList (non-generic) and IReadOnlyList<T> have nothing in common outside of IEnumerable
Kai
Kai•3y ago
IEnumerable should just not exist in modern .NET but yeah legacy code... Also I don't really understand your issue. Imo it doesn't make sense to ever have a type that implements IReadOnlyList<T> and INotifyCollectionChanged but not some kind of IList(<T>) Given INotifyCollectionChanged only makes sense if the collection can actually change, but IReadOnlyList<T> explicitly can't change Like, in what case would the event fire?
RazorSharpFang
RazorSharpFangOP•3y ago
My point is that IList<T> extends IReadOnlyList<T> Supporting a viewer that works with IReadOnlyList<T> by definition must work with IList<T> Presuming that the interface contract is implemented correctly
Kai
Kai•3y ago
due to legacy reasons that 's not true though IList<T> does not extend IReadOnlyList<T>
RazorSharpFang
RazorSharpFangOP•3y ago
👀
Kai
Kai•3y ago
yup.... IList<T> is .NET FX 2.0 and IReadOnlyList<T> is .NET FX 4.5 :/
RazorSharpFang
RazorSharpFangOP•3y ago
Oh and here I thought ICollection<T> : IReadOnlyList<T> What on earth are these interface angryowo
Kai
Kai•3y ago
✨ legacy code ✨
RazorSharpFang
RazorSharpFangOP•3y ago
And you have a whole bunch of classes that implement IList but don't implement IReadOnlyList<T> now?
Kai
Kai•3y ago
not really I mean .NET types all implement both iirc it's just the rare externally implemented collection type might be weird now Do you actually have a type that implements IReadOnlyList<T> and INotifyCollectionChanged, but not IList(<T>)????
RazorSharpFang
RazorSharpFangOP•3y ago
It implements IList<T> But not non-generic IList I was under the impression that IList<T> : IReadOnlyList<T> But that is clearly wrong.
Kai
Kai•3y ago
oh that is actually somewhat reasonable and imo an oversight in avalonia
RazorSharpFang
RazorSharpFangOP•3y ago
Ah, but maxkatz6 says by-design. Perhaps they thought I knew that IList<T> does not extend IReadOnlyList<T> I am not so competent, clearly.
Kai
Kai•3y ago
I think the part of your issue that says IReadOnlyList<T> is by-design, but that it doesn't support IList<T> is a valid problem imo can't imagine they disregard that too as by-design 🤔
RazorSharpFang
RazorSharpFangOP•3y ago
Okay but I feel like it would weird to close this one and then immediately raise a new issue about not supporting IList<T>
Kai
Kai•3y ago
looks like they are fine just discussing it as is?
RazorSharpFang
RazorSharpFangOP•3y ago
Yeah, maybe I'm just overreacting to the label change
Accord
Accord•3y ago
✅ This post has been marked as answered!
Want results from more Discord servers?
Add your server