❔ [Unity?] How to have a list of generic classes in inspector cast as derived class
I have some classes as follows:
In my main script I am attempting to have a list of Tracked Markers in the inspector, But if I initialize my list as
Then when I try and cast it later, I get the expected
I somewhat understand why… If it was stored in the baseClass list, it would not know which child it belongs to. However in unity the objects that I am slotting in are already the derived class… so it should be available.
32 Replies
Examples online that have changed TrackedMarkers as seen below have not worked for me, but perhaps I misunderstood the full implementation.
It looks like a Covariance problem
yeah
it has nothing to do with unity
also don't use
as
use casts where possibleI figured it didn't but just in case the issue was related to unity, I wanted to make it known
Changing to casts does not fix the error, but it does change it.
error CS0030: Cannot convert type 'TrackedMarkers<MarkerScriptable, MarkerInterface>' to 'TrackedMarkers<Scriptable1, Marker1>'
that's because
as
does a runtime attempt, and returns null. Explicit cast lets the compiler check the covariance/contravariance problem for you. You'll need to use an interface for contravariance :
SharpLab
C#/VB/F# compiler playground.
I am working through the changes you advised, while I am going through the following situation showed up.
This function is in ITrackedMarkers
Which I think is impossible? From my reading I cant take U as an
In
and Out
, but all I am trying to do is add it to the list
Sorry for not showing that up front... I did not realize it would make a difference.oh yea sorry, I don't think
out
is actually needed
so my interface needs every variable / function prototype? but the main logic stays in the class?
you can technically do it in the interface with default implementations in interfaces
or even just cast to the concrete implementation
is a valid cast
You use a lot of setters, and it looks like I need to to that in both the class, and it's interface.
This creates a problem for fuction calls that use
ref
.
Is there a better workaround than lots of temp vars?ref getter property
there's no other good way to achieve that
PropertyInfo is a thing, but don't use it for that
Have an example? a quick google does not show me much.
I am not used to using properties since they don't play super nice with unity
Something like this?
then pass the
_tag
by ref?no
or don't use ref and just switch to properties
add
[field: SerializeField]
on the property declarations
then it's the same editor experience as fieldsYou all were able to help me get it back to compiling... which is great!
But, runtime casts are still no good.
As a note, I set the first element in the list (in editor) to be of the correct type
SharpLab
C#/VB/F# compiler playground.
ah the guy that wrote the examples above forgot to put
out
on the generics
but ref
won't work with that
you have to do get setout
does not work with the Add(U u)
function which takes a U
as a parameter. That's why they removed it
I added out
to both T and U, but the same runtime exception existshttps://sharplab.io/#v2:C4LgTgrgdgNAJiA1AHwIYCMDOwyoMbAAEAAgEyECyqYA1gKZgCSUwDAZvnQLABQA3rwC+vXhmy4CJclVoMAynjABLAA7AMAG278hInmUrV6YAIyEQh2UxbtOhXgJ7CevAzOPkL7hs1ZgOeNqOzq7kCspqmnRmXkbyiqrq6FoOui76YQmRyXSelsbhiVGpTnp6Sjb+dowAKhL0cN5gmAA8APYQRDUwhB1EAKoAfLyEo4QA7gAWDHSENeb58RFJKTxjE9Ngs/0LTb62gSXrxCYADITqAOaEfISXdMAA3ITOxwDMcxc3dw/Pr2PED79ADaAF1CBBvvcni89McACyEACCcDgAAodhAAJSPNKhOb1OiNOLNFrdQhDBa1QnEqytclDEZjKYzT6xKyFbKrdYsrYU3Yk/ZVQ46NYAj4nc5XKG/QiYWX/UaAz5EW7Q57ymGKkhAsEQmUwzV/JmjE06kiIlHozFYvjOEIZEgmADsRwBJgAbBbDBU0VizY51usAG7UQgaJTYQgAXkIUDo4yd8IAdAAZSPAFrU/ANJqtJqclZ0Hp7SoBOiDQZ+3FioPhjPJq1o+OJuo5ol5loFrJFkuCsucKtYnFm9ajsahsCEPCobBEmOENHZvC5kmtQtREx9qwmQZYiPYYGnUE19b2oA==
With a little bit of tweaking I was able to get this error. But it's warning me that I can't be Co and contravariant... I think
SharpLab
C#/VB/F# compiler playground.
Falling some other examples online. I attempt to split my interface into a covariant, and a contravariant part. No dice
https://sharplab.io/#v2:C4LgTgrgdgNAJiA1AHwIYCMDOwyoMbAAEAAgEyECyqYA1gKZgCSUwDAZvnQLABQA3rwC+vXhmy4CJclVoMAynjABLAA7AMAG278hInmUrV6YAIyEQh2UxbtOhXgJ7CevAzOPkL7hs1ZgOeNqOzq7kCspqmnRmXkbyiqrq6FoOui76YQmRyXSelsbhiVGpTnp6Sjb+dowAKhL0cN5gmAA8APYQRDUwhB1EAKoAfLyEo4QA7gAWDHSENeb58RFJKTxjE9Ngs/0LTb62gSXrxCYADITqAOaEfISXdMAA3ITOxwDMcxc3dw/Pr2PED79ADaAF1CBBvvcni80rwKn4ArNavU6I04s0AEp0FRtFrdQhDBYo/ANJqtAlDEZjKYzT6xKyFbKrda0raE3YY/ZVQ46NYAgAshAAgnA4AAKHYQACUjzhGTmqPRVgpPSJFhJeDJGMw2Nx+LVw35ozZs3mDIKWRW2lZm22nKs3KRRwBHxO5yuUN+hEw3v+o0BnyIt2hz19MP9JCBYIhXph4b+1NGSajJCFoolUulfGcIQVJwA7C6AyYAGxpwwVcXSlOOdbrABu1EIGiU2EIAF5CFA6OMSCYBQA6AAybeALU12pVerxTSZ1p6e0qSMGg2rcuN9db2EHGfFPb7dVJaPJLTnVqii65y84a+lspT60fYybYEIeFQ2DRncI4snJ51GcWnnKITCvKwTEGaVt2AYFTlBDd1lzIA=
SharpLab
C#/VB/F# compiler playground.
yes it won't
you can't return an array either
because it's mutable
change the array type to ReadOnlyCollection I think, then it will work
read the error bruh
it's about nullability
I saw warnings about nullability, but perhaps I am misunderstanding the error there.
I changed it to a ReadOnlyCollection, and then removed the nullability errors by adding a constructor. But I still get the invalid cast at runtime.
https://sharplab.io/#v2:C4LgTgrgdgNAJiA1AHwAIAYAEqCMAWAbgFgAoDbHAOgGEB7AG3oFMBjYAS1qgGdKB5AEYArVsACytOE3rESpAIYDuwMPLbYATJjHywAayZgAklGCGAZmqaYA3gF8FSlWuCbtug2ADKLMOwAOwIrMtg5kWjr6hjiYIO5RxqYWVqGkqBEehlpxkZ4mZmCWLNb2aVo+foHBTDE5md6+AUECIaXhmBVN1dnxnp1VLSVhpKTsSYUpRgAqqiwGcLmG3AA8tBCuUzCYAKoAfKSYh5gA7gAWhtZTsb2G/c3MB0dnFzvXi4kFRUykNo+HuFgggBzWyYIFMYAETBhI7YADMmCurhsYIhUJhR1QCIASkx5HA+FB6ABPOiMUScKDLPaYCCg8GQ6GkYYkMafSYzNTzd7cXH+WjLTY7XbXaazbn1FZCvZ/E7nMCXN71O7VWXPBWvOoJfLJYo/WWoPCYACCcDgAAptrSAJSyFnpRHipgLSWCrY0uJirnOnl8gXS/YkWHqxVavqNAYPINPeXWK1hww6iZ6ki/aP/BEAzDA+lozDcPMYjOI7O5xkFxlF+GYXH4wkksnMNiU6kiukohlQivo2X+PwAN3kZkwABl2MpW5gAPrt1Hlwuyg2Zo2mi1WiDWtqwxfp6ucuY+yXmq5jKfAa2ytOw2E5gC8mAARA/ZNejq576fIbLYTPMPeoEwxyjuOwCtuatrfkcdL/oBNZ4gSRKkgwTYcFwYEzhBu5hPaWi4AA7Pqu64AAbNgRo6GM4GXpBhyDmAmD0CBf6YABQG4HglBjhOXoHi6CS8kw/LLO8KqDFs7xJl8uy7OBL6vpgNEdBG9w1PmMQwUBonMDgsmKYxyiUKu5qsY63p8Z4Kwicp1TifUklWDJ3A4NamHyQpu6wnRmAsPIyjOsx5o8RK/F+ssWk1LZCQ4Ls1r6cAADa6AALpyYc2FAA
SharpLab
C#/VB/F# compiler playground.
isn't that an upcast? how would that work?
the list quite literally is not an
ITrackedMarkersRepo<Scriptable1, Marker1>
(U
is not Marker1
)i am not sure I am following.
I was under the impression that co/contravariance worked in exactly that fashion.
you don't specify a variance on
U
that is because U when set as a read only collection seems to state that it needs to be invariant, I could not find a way to set it to out
If I were to use an
IReadOnlyCollection<U>
I am able to use out U
in ITrackedMarkers<out T, out U>
.
But I get the same runtime invalid cast exception.that interface has nothing to do with the repo interface
you're casting to the repo interface
for which U is not out
that won't ever work
if you want to add items in such generic way, you have to either hide it polymorphically under the object you're trying to add, or make another class that's responsible for adding items, or make a method that takes
object
and tries casting to U
you can't make that work with interfaces
that said, if you make U on the repo interface in
, you'll be able to add a more derived object no problem
but there's no benefit to that in your case
if you stop and think about it carefully, you'll see it makes sense
and whatever you're trying to do (that add thing) doesn't, from the type safety point of viewI am absolutely happy to change as many things as necessary here. I even have some ability to change the actual functionality of the class. Maybe I can find a way to not use that add function at all.
I'm just really looking for a way that I can have all of these different objects in an enumerable of some kind
The thing that I'm working on is about to go down that nasty rabbit hole of having 50 of the exact same item, with no changes between any of them except for the types.
Each of these items has a boilerplate copy and paste, and then in half a dozen places scattered around the code base needs to have the exact same chunk of code copied and then the names changed for this item.
My goal is to prevent that. Maybe my starting premise was wrong to begin with
if it's copy and paste, then use composition
you can pull common things out into another type, and have a field of that type
So rather than having a base : derived...
I have a base<T> and the T is my
fake derived
?
I still don't see how that helps me get a list of all the types
Ah wait... I think I am seeing where you are goingwhat
congrats, you just derived from both a and b
but in all seriousness, use the component system
either the behavior one, or the data oriented one
either one is designed to help with that
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.