✅ Receiving any instance of a generic class in a method, no matter what the generic type is.
Title, how can I allow for a method to receive any instance of a generic class, no matter what the generic type is.
So a method that could receive both Generic<int> and Generic<string>.
Doing public void MyMethod(Generic param) doesn't work
101 Replies
An option would be to have a non-generic superclass, but is there another way that doesn't force me to inherit?
uhm, can the method itself be generic?
^
That would solve it, but no
then ya fucked
Hahah
So I'm stuck with creating a superclass just so I can reference the object?
¯\_(ツ)_/¯
MyMethod<T>(MyGeneric<T> x)
is the "proper" solution I'm afraidIList
maybe...?
You lose the generic, thoughMaybe I can be more specific:
I have two lists of GenericA and GenericB. Both inherit from NonGeneric.
I have a façade that creates GenericA and GenericB, and stores those in an internal list to the façade, so that later I can call a method that deletes those Generics.
When creating the Generics, obviously I need to pass in the type.
When cleaning up, all I need is a way to remove it from a list
I could accept types of "NonGeneric", but then My cleanup method for types of GenericA is different from types of GenericB, so I'd have to do some type checking to guarantee that the user passed a GenericA into CleanupGenericA and not a GenericB
Does this make sense?
Stack Overflow
How to cast Object to its actual type?
If I have:
void MyMethod(Object obj) { ... }
How can I cast obj to what its actual type is?
That would be the same as having the method generic, no?
I'd rather use pattern matching
Pattern matching is better... Yeah
I wonder if that works, considering covariance, contravariance, all those shenanigans
I'm confused about this IList
Why?
It's just an interface inherited by List
Unknown User•16mo ago
Message Not Public
Sign In & Join Server To View
Right, in my case I'm not receiving lists
Unknown User•16mo ago
Message Not Public
Sign In & Join Server To View
Angius
REPL Result: Success
Result: <>f__AnonymousType0#1<IList, bool, IList, bool>
Compile: 483.590ms | Execution: 77.641ms | React with ❌ to remove this embed.
What are you receiving and what is your end goal?
Ah, yeah, a generic class
You could use a marker interface the very same way
Just an empty
interface IStuff {}
Right
And then pattern match it as needed
Maybe since the language isn't allowing a simple solution for this, the desired goal is incorrect?
Perhaps. I might be sticking too close to my python background which is a bit more flexible in this regard
And is the signature of your.method constrained? Can you add extra parameters?
I can add extra parameters, yes
I can give a concrete example
Crazy idea
Well, again, it would be best to make the method itself generic
Maybe you could add a parameter for a method delegate that would do what you need with type.
And why again can't you use generics?
I mean a generic method
I can
Well
Problem solved then
But you said this
I was overly enthusiastic
🤔
Nothing is effectively stopping me
But I would like to avoid it
why
I just have a construction method and a deconstruction method. Didn't want users of the API to have to repeat the type of the constructed object in the deconstruction
Oh, well then don't create these challenges for yourself
"Nothing stops me from using a spoon to eat this soup, but I would like to avoid it"
I use a knife to eat soup, was I doing it wrong my whole life...
Well you can just make the class itself generic, then
Then it will propagate to the methods, the ctor, the dtor, everything
It's a static class
oof
Wait
Why does a static class have a constructor
And a deconstructor
???
Static constructor is ... fine
Sorry, shouldn't have used those words
Not even "why", "how"
But a deconstructor?
The class has methods to create and destroy instances of my generic classes
Wait
Maybe share the class?
This would clear some confusion
Some sort of
?
I'm getting more and more confused by the second lol
Confusion go brrr
Sorry! I'll create a concrete example of what I'm doing and share it here, since I can't share the source code
$code
To post C# code type the following:
```cs
// code here
```
Get an example by typing
$codegif
in chat
If your code is too long, post it to: https://paste.mod.gg/Just in case
I'm aware, but thanks, appreciate it :)
Okay, I think this might be a good example
Example usage:
So it's a weitd singleton kinda thing?
A substitute for having straight out global variables?
Yeah, its an Event Aggregator
But I have a layer in front to create all my Publishers and Subscribers
So the user doesn't have to know about all the intricate details and instead can just worry about using the entities it creates
Well, my first instinct is "static bad, don't do that, use DI or something instead"
In the example usage you create a publisher. Imagining that you do not use generics... How would the method or the user know what generic type is created?
And yeah... Maybe DI or mediator is something you should consider using
Well I currently have this working by passing the generic type in as a parameter instead
So:
The user of a C# library would prefer generics in this case
I suppose I could do this:
and the rest of my code looks the same, and the user would still have the generics
Yes, not sure why you need to get the typeof
Because you create generics simply by
new Generic<T>()
I mostly do it to validate that no other publisher is created for a given topic with a different type
So I can't create a Publisher for topicA with type int, and a Publisher for topicA with type string
Ooook, thinking
Yes typeof should be fine
Cool, I'll give that a go and report back
Could you give me a bit more information as to why this is your first instinct?
I think I know why but just to get your point of view
Actually, I take back what I said.
At one point I loop through the TopicSubscribers and call subscriber.ReceiveMessage(message), where message is of the type that was given. Problem is that since it's not a generic, message has to be an object to allow for anything to be sent. If it's an object, when the client receives the message, they will have to cast it to their type, which is even more of a problem
I feel like that message was confusing
It gives unrestricted global access
Breaks encapsulation and all that good stuff
Can you explain how DI doesn't do this?
I need to explicitly inject a given singleton where I need it
Only then does it become available
If I don't inject it, I have no access to it
This might be my lack of experience talking, but you do have access to the DI framework itself, isn't that in a way something you can access everywhere?
I have access to serives registered in the DI container only in other services also registered in that container
So no, not global either
Everything's on an opt-in basis
But something somewhere has to be global, no?
You need to somehow be able to say "hey, I want this reference", and however you do that, must be something that is global
Maybe its an attribute that marks something so that the DI framework knows what to inject
No, nothing needs to be global
If I make a random
class, it will not have access to the DI unless I explicitly registed it with, say
Again, my lack of experience is showing.
Could you explain what you mean by "have access to the DI"?
I thought DI was something along the lines of
Yes, sure, you can do that
But only if
Foo
itself is registered in the DI containerSo you have a class somewhere that handles all these registrations?
The main method, for example
Sure, but then at that level you need to have everything available.
So if you have 100 entities you need to call a registration method 1 time for each entity (100 times total)
If it is a generic one, you can register it once, I believe
But yes, for each entity type, you have to register it
What matters is you need to be explicit about it
E.g., you register a logger that is used thoughout the app
Right, you set the logger to some type of app-level scope and the DI framework creates one logger and everyone uses the same one
The same type
Same type or same instance?
Not the same instance, unless you configure it
If it is scoped that way
Samenisntance if you configure it as singleton
Yes
Right
I do still have a hard time making the connection that "it's intuitively better to just jump from the system I'm implementing to a DI framework"
When what I have is effectively a number of events that I can invoke at any time, and a number of observers interested in those events
But a central place to register those observers on the events
With an abstraction over the top to simplify the api
If I was using DI I'd have to have one point where I'd register all my events, and then both invokers and observers would have to request a reference to that event.
In my system, it's all abstracted behind one class.
Sure, but I can, randomly, from anywhere in the code, call
Facade.RemovePublisher()
I could do that in the finalizer of a DTO
Or in a property getter in a record
Or in a Razor template
It's unrestrictedSure
But if we are coding on the principle that the user is dangerous, then we need to safeguard against everything
Yes
Hahah
I guess I should have seen that coming
Although, I could argue that the user can still configure the DI framework so they can call RemovePublisher from a DTO
or from anywhere really
Sure it's more contrived, they need to add more lines of code to be able to do something that isn't ideal, but they can still do that
Yes, but they are being explicit about wanting to do that
Injecting a
IPublisherService
into a class is an explicit statement of intent that this class will do stuff with publishersWell, to be fair, I do think that my system is quite explicit:
If they create and store the publisher, then they are going to do something with publishers
But I think I do understand what you are saying
https://martinfowler.com/articles/injection.html
This I think represents a little bit what we are discussing
I think it's more of a matter of where you want to be explicit, not as much as if it is or isn't explicit?
"The first point is that both implementations provide the fundamental decoupling that's missing in the naive example - in both cases application code is independent of the concrete implementation of the service interface. The important difference between the two patterns is about how that implementation is provided to the application class. With service locator the application class asks for it explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class - hence the inversion of control."
(highlight is my own)
Anyway, sorry if I derailed the conversation, but it did genuinely help me understand some more concepts!
Thanks @ZZZZZZZZZZZZZZZZZZZZZZZZZ and @Denis for the help, and thanks for the genuinely interesting conversation! :)
Anytime
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.