C
C#2y ago
Loup&Snoop

✅ Class as a field?

Suppose I have Class1, Class2, and Class3. Class2 is just a container of information. At runtime I want Class1 to look into the contents of Class2, find Class3, and instantiate an instance of Class3. For this, I DO NOT WANT class2 to have an instance of class3, and I do not want class2 to have any code/knowledge of what class3 is going to do. In theory, I want Class2 to have a field which gives a type that implements a specified interface that allows Class1 to call it. Is there a way to do this?
53 Replies
Loup&Snoop
Loup&SnoopOP2y ago
wouldn’t that require the class to hold an instance of the type with the interface? well, the goal is for class2 to be immutable. So it should only be able to tell Class1 that it needs to instantiate a Class3 as there could be a Class4/5/6 also that all implement the same interface. And different instances of class2 would refer to different classes, if that makes sense I’m not sure how that would work class2 could have a method to output a reference to a new instance of class3/4/5, but the point still stands that class2 needs to be able to hold information of what class3/4/5 are without an instance
ero
ero2y ago
abstract class Class2Base
{
abstract IFoo CreateInstance();
}

class Class2<T> where T : IFoo, new()
{
override T CreateInstance() => new();
}
abstract class Class2Base
{
abstract IFoo CreateInstance();
}

class Class2<T> where T : IFoo, new()
{
override T CreateInstance() => new();
}
interface IFoo { }
class Class3 : IFoo { }
interface IFoo { }
class Class3 : IFoo { }
I kept it a bit more generic, allowing for a non-generic Class2
Loup&Snoop
Loup&SnoopOP2y ago
i see. This might be out of scope, but I’m trying to make this in an asset file in unity as a scriptableobject. The idea is for Class2 instances to mostly exist as files which are never modified during runtime. And a generic would require me to instantiate a new Class2 at runtime, which is not desirable. Sorry that I didn’t make that clear.
ero
ero2y ago
It's definitely still not clear lol How could you possibly modify a file during runtime
Loup&Snoop
Loup&SnoopOP2y ago
ScriptableObject instances are stored in files. Class2 : ScriptableObject, and I want instances of Class2 to never be modified or instantiated at runtime. If I have Class2<T>, then some code needs to have knowledge of Class2’s connection to class3, and I would need to instantiate Class2 as a generic.
ero
ero2y ago
If they shouldn't get instantiated at runtime, then what purpose do they serve
Loup&Snoop
Loup&SnoopOP2y ago
So something would need to make new Class2<Class3>. But also, if I had something with knowledge that class3 is supposed to be linked to that specific instance of Class2, then I would be done.
ero
ero2y ago
Just delete the class lol
Loup&Snoop
Loup&SnoopOP2y ago
Class2 contains data for TileObjects in a game. Things like sprite, gamelogic, tilelayer, name, etc. Class2 describes the data. Class2 instances are files with those fields filled out for a specific type of tile.
ero
ero2y ago
Now we're getting somewhere
Loup&Snoop
Loup&SnoopOP2y ago
Class2 only needs to store knowledge that it has a link to Class3. class2 does not store an instance of class3. It just needs to be able to articulate to another class (class1) to go instantiate a class3 and call code from it. So if class1 asks: I’m looking for the ITileScript associated with you. Class2 can respond: That would be Class3:ITileScript. Or Class4:ITileScript… I hope that makes it more clear
ero
ero2y ago
interface ITile
{
// ...
}

interface ITileDescriptor<ITile>
{
// ...
}

sealed class Ground : ITile { }
sealed class GroundDescriptor : ITileDescriptor<Ground> { }
interface ITile
{
// ...
}

interface ITileDescriptor<ITile>
{
// ...
}

sealed class Ground : ITile { }
sealed class GroundDescriptor : ITileDescriptor<Ground> { }
yes?
Loup&Snoop
Loup&SnoopOP2y ago
is GroundDescriptor the Class2 here?
ero
ero2y ago
I would say so
Loup&Snoop
Loup&SnoopOP2y ago
that makes sense, but I can’t really serialize that
ero
ero2y ago
How so?
Loup&Snoop
Loup&SnoopOP2y ago
well, Class2 is like TileData. If I want to do this, then I would need to make an interface and child class for every different type of tile, just to be able to make an instance that is a child of TileData so I could have a file of the child, which has the generic part filled out explicitly
ero
ero2y ago
You need to explain what you mean by "file" You keep saying that and I don't know what it refers to
Loup&Snoop
Loup&SnoopOP2y ago
i can copy, move, delete it on my hard drive i could drag it to a different folder and all that. a literal file
ero
ero2y ago
I don't understand how a file corresponds to a c# class
Loup&Snoop
Loup&SnoopOP2y ago
Class2 describes the rules for writing and parsing the contents of the file, as though it is an instance of class2 So if I do: public class Class2: ScriptableObject { int i; }. Now I can make files, like Number2.Asset, which corresponds to an instance of class2 with int i, and is accessible as such.
ero
ero2y ago
WhatChamp
Loup&Snoop
Loup&SnoopOP2y ago
And I can make Number5.Asset, which encodes another instance which just has i =5.
ero
ero2y ago
Incomprehensible lmfao
Loup&Snoop
Loup&SnoopOP2y ago
Then Unity just lets you read that at runtime, so you can pass in the file as an instance of the class so I can drag Number2.asset and Number5.asset, to a script that takes two Class2, and then that script can read the values and do stuff with them this is getting outside of the scope of the original question
ero
ero2y ago
I mean I think it's necessary to explain this to even comprehend what's going on
Loup&Snoop
Loup&SnoopOP2y ago
ultimately, I would like to store a class as a field. Not an instance of a class, but information that can be read to point to a specific class. So i can have a class2 with a property that returns the type of that class3/4/5
ero
ero2y ago
You also choose to abstract away a lot of info. I think in this case it would be better if you just gave a complete example and your goal API
Loup&Snoop
Loup&SnoopOP2y ago
When a tile collision happens, TileHandler looks into an instance of TileData:ScriptableObject associated with that collision. TileHandler wants to get a type that implements ITileScript associated with TileData. ITileScript has a method that (when implemented) is supposed to do something specific for that tile. TileHandler calls ActivateCollidedTile, which is a function in ITileScript. Then I can have something like: GroundScript :ITileScript, SpringScript:ITileScript… Then TileData GroundData contains a field that tells TileHandler that the ITileScript associated with it is GroundScript.
ero
ero2y ago
Can you just post the code in a condensed form This is impossible to understand for me
Loup&Snoop
Loup&SnoopOP2y ago
i just want to store an object of type Type in my class T.T as a field no generics instances cannot be created or altered during runtime
ero
ero2y ago
There wouldn't be any altering at runtime just because you use generics What you're asking is just nonsensical is all
Loup&Snoop
Loup&SnoopOP2y ago
to have a field of type Type?
ero
ero2y ago
Yes, it sounds like very bad practice I can't tell if it's a proper solution because what you've explained doesn't make sense to me
Loup&Snoop
Loup&SnoopOP2y ago
why would that be nonsensical specifically, a field of type Type with the restriction that the Type in the field implements a particular interface
ero
ero2y ago
That must involve generics You can't constrain anything without generics So then please. Ask your question once again, without trying to abstract anything away, with as much detail as possible, and the complete architecture, as well as the goal API you want to see. You can skip including any unnecessary members obviously
Loup&Snoop
Loup&SnoopOP2y ago
Class1 gets an instance of Class2. Class2 instances need knowledge of a specific class implementing a common interface (ITileScript). Class1 looks into an instance of Class2 to know what class that is, and calls a method guaranteed in the interface implementation
ero
ero2y ago
Why are you writing it out in words Please just post code
Loup&Snoop
Loup&SnoopOP2y ago
i can’t post code that doesn’t exist
ero
ero2y ago
sounds here like you have plenty of code
Loup&Snoop
Loup&SnoopOP2y ago
i have none of the code relevant to this discussion
ero
ero2y ago
So you're solving a non-existent problem...?
Loup&Snoop
Loup&SnoopOP2y ago
I am not going to code an interface and class that cannot be accessed that’s basically where I’m at
ero
ero2y ago
I don't understand anything lmfao
Loup&Snoop
Loup&SnoopOP2y ago
no idea, but probably not without great difficulty or learning something that would let me do that I could maybe store a string that gets parsed to a class, but spelling issues and slow lookup etc…. it’s way too unsafe i’m working in unity lol but any string => code conversion is always unsafe
ero
ero2y ago
I mean just because you're in unity doesn't mean you have to use bad architecture
Loup&Snoop
Loup&SnoopOP2y ago
i’m trying to refuse to use a string to call a class name. That is really a separate issue from trying to store a field of type Type well I would rather have a Type that needs to implement an interface what I’m trying to convey is storing information about a type and not holding an instance
ero
ero2y ago
So for this, why did a generic argument constrained to an interface not work? That seems like the perfect solution
Loup&Snoop
Loup&SnoopOP2y ago
Because unity serialization, mostly i gtg back to work. I’ll keep thinking about it tho
ero
ero2y ago
What's serialization in unity exactly? You wouldn't need to serialize this tile info would you? So then what's wrong with this? I don't think this should have any issues with serialization?
Loup&Snoop
Loup&SnoopOP2y ago
I found a solution. There’s a package called ClassTypeReferences which makes a serializable reference to a class type.
Ezlanding
Ezlanding2y ago
If I’m understanding this correctly, why not just serialize an enum and make a factory method to generate the class based on the value of the Enum?
Accord
Accord2y ago
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.

Did you find this page helpful?