Store generic Func T inside a colletion [Answered]
I have a generic Func<T>, which i wan't to store in a Dictionary, but i don't know how to do that since apparently the restriction of T is not enough
72 Replies
I have this method which takes a Func<Context, Packet, Task<bool>>, and Packet must be an IPacket
I don't know how to store that in a dictionary
This is not valid, despite Packet being an IPacket
You can't
Not without doing horrible code like Akseli showed (seriously don't do that)
This about it this way:
Oh yeah i get it. I guess that ill need to save the MethodInfo instead
Thanks
U could also store a delegate
if its used correctly its completely safe and works, its the correct solution if you care about performance
another solution is to just
Use a proper cast, not
as
, if you don't expect the cast to failNo it is not. The proper solution is to design a type safe architecture. And as canton said, as is a bad idea in that nested lambda example
sometimes you need to sacrifice safety for performance, besides its completely safe to use in this case, it can never fail in the current context
That's a very bold assumption. Never assume that someone, particularly someone who is not super familiar with type safety, is going to use it completely correctly
thats why i said in the current context
Recommending unsafe code to anyone not in #allow-unsafe-blocks or #advanced, especially without any explanation of why it could work, or how it should never be misused, or how you need to actually use reflection to get it back to the original function type, is a very bad idea
agree with that, my bad.
Like, seriously, if someone isn't understanding these dangers, don't just post a code snippet on getting around the type checker
well this is a safe solution, it cant cause any runtime errors, only a null exception from the other side if as is returns null
also what do you mean you need to use reflection to get it back to original type? Using Unsafe.As thing you dont need to do that
If you ever need to extract that lambda again, then yes you need to use reflection to get a Type you can Unsafe.As on
if they extract it from the dictionary they can use it as <Context,IPacket,Task> it will work
Caches often need to return things beyond immediate usage
Without seeing the rest of Stay's code, we can't say for sure how the values in this dictionary are going to be used
we can assume what he wanted from what he said
All that was said was storing in a dictionary
Not how it would be retrieved
thats out of context of the question
he asked how to store it
It's important to the context of the question if you're making a recommendation that will significantly affect the storage of the thing
Like, you're assuming that there's only reference types implementing IPacket
that doesnt matter because when you retrieve the func with IPacket signature, the value type will be boxed to IPacket when calling
the method will still work as its supposed
... No
If the func takes a concrete value type, and you pass a boxed value type, it's not magically unboxed
It's just broken
yes...
if you had a value type
Packet pkt; that implements IPacket
and you call a method with IPacket parameter it will be boxed
You're not calling a method with an IPacket parameter
You Unsafe.As'd it to be such, but it doesn't actually have that parameter
but you are retrieving it as IPacket parameter
from the dictionary
That's the problem
You end up passing a boxed Packet to something that takes an unboxed packet, and nothing is going to do that unbox
It'll just fail
then you would just have to have packet as a class
Orannis#3333
Like, you're assuming that there's only reference types implementing IPacket
Quoted by
<@!269674004065943552> from #Store generic Func T inside a colletion (click here)
React with ❌ to remove this embed.
sure its an assumption, could ask the OP for more details
All of these caveats are why you should be careful when making recommendations of unsafe code
Especially in a channel where the nuances and implications of it are probably not well understood
Especially given that the alternatives to using Unsafe here are pretty painless and cheap
using Reflection is not cheap..
You don't need to use reflection here
- MethodInfo is reflection
Who said to use MethodInfo?
well, thats what the OP took
Sure, but there are solutions which don't require reflection or Unsafe here
like this
Yep (although don't use
as
). Or ones which cast the whole delegate to Delegate/object and back. Those are the sorts of solutions to push IMOYes, though as does not work there
Literally won't compile
it works
No it doesn't
atleast it should, ive used this technique before
maybe you need to add a type
Packet is not known to be a reference or value type
Can't use as on it
as
is the wrong thing to use there anyway. If you mess up and the cast fails, you get null
passed to the delegate, which is probably going to cause an NRE somewhere down the line, and you'll have fine tracing it back to the bad cast. If you use a proper cast, you get a nice InvalidCastException
at that point, telling you what you did wrongright, yeah you need to use a cast, i didnt check if it compiles or not just threw it from memory on my phone
I'm back. Yeah, i understand why what i was trying to do yesterday at 3 am doesn't work now
Anyways, here is a bit of context of what i'm trying to do in case that there is a solution better of what i currently have
I'm trying to add a easier and faster way of handling packets in my application, i thought of doing something like this
I know that i could do this
But that would require of casting on the handle method
Which is not the end of the world, but it's what i'm trying to prevent
Yeah looks familiar. I'd probably wrap the delegate in another one which does the cast for you, like this https://discord.com/channels/143867839282020352/1010669940887539722/1010860845410029599 but with a proper cast rather than
as
Akseli#8820
another solution is to just
Quoted by
<@!660066004059029524> from #Store generic Func T inside a colletion (click here)
React with ❌ to remove this embed.
If it's networking, you're not going to care about the extra delegate invocation
Yeah, that's probably also faster than MethodInfo, right?
Probably not too far off - the cost there is getting the MethodInfo, but you're caching it. But yeah slightly cheaper, and certainly more readable and safer
But MethodInfo requires an object[], which would box the struct behind IPacket
(as far as i know)
Yep, but that's being boxed anyway. Interfaces are reference types
So assigning the struct to IPacket boxes it
Oh i didn't know that
Thanks, i'll use this solution then
How do i mark this thing as solved? First time using discord threads
$close
Not that, heh
Ask the thread owner or member with permission to close this!
Ah, with
/close
nice
✅ This post has been marked as answered!
This is absolutely not correct. It is not, by any means "completely safe". It may work today in some cases, but it's undefined behavior and it might (and will) break down in several scenarios. Yes, even if you're using "the right types". It's not something that you should be using even if you think you know how it works, it's just not correct code. Nobody should use that, period
we already had this conversation and went over the cases where it wont work
Right. So you're aware that code is not valid. Then don't recommend it to people online asking for help
Actually wait, no, I think we're not talking about the same thing here
its not valid in all cases, no
No. In no case
There is no case where that code is safe
I know you think you know. You don't
add a class constraint to Packet and its safe
if you dont do changes
it is not
I literally had this conversation with the actual principal architect of the .NET runtime (Jan). This is not safe, ever. Period
okay, i believe you, can you tell me why its not safe? so i can learn
"I think the highest risk of incompatibilities come from codegen optimizations. Some of the advanced codegen optimizations assume type safety. Your code may break in odd ways with type safety violations."
"Yes. For example: The delegate can be bound virtually. In future, we may do delegate inlining and speculative devirtualization for this case. Is it going to work properly when some of the signatures involved violate type safety? I would not bet on it."TLDR: the runtime and compiler assume type safety is never broken. Even if you're using "types correctly" here, things can still break down at any time because this is fundamentally undefined behavior, and other components might be doing things with some assumptions which you're breaking there Just don't do this 🙂
hmm makes sense
i could argue against it but id rather take the L
to learn
L for Learn