Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

class with a special variable

Discussion in 'Scripting' started by twilightZone, Dec 28, 2015.

  1. twilightZone

    twilightZone

    Joined:
    Oct 10, 2014
    Posts:
    30
    Hello all,
    I have a problem to create a class.
    My problem is this one :
    The variable 'value' can be a string, an integer, a float or an arrayList.
    Dynamic variable does not exists. is it possible with a little code in the class ??

    Thanks

    Code (CSharp):
    1. [System.Serializable]
    2. public class Foo
    3. {
    4.      public string text;
    5.      public int number;
    6.      public ???? value;
    7. }
    8.  
     
  2. Nigey

    Nigey

    Joined:
    Sep 29, 2013
    Posts:
    1,129
  3. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @Nigey, that only works for local variables.

    @twilightZone, I assume that you need serialization in your case which makes it more complicated. You have the possibility to make the class generic, but you would then be forced to create subclasses without generic parameter in order to make it serializable. Or you could implement a custom serialization.
    If you could share a few more details about the reason why you need this, it will most likely be a lot simpler to help and not just guess what might work in your case.
     
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    You can use the 'object' type. BUT... I see you've used the System.Serializable attribute, which would suggest that you want this to be editable in the Inspector. An 'object' type won't be.

    If you know that the last variable could be one of a set number of types, I would recommend having all of those types there, with an enum suggesting which one of them you want to use. You can then make an accessor property that hides this all away on the code side, and/or a custom inspector or property drawer to hide it all away on the inspector side.

    Alternately, you can make a base class without these things and a derived class for each of those possibilities, however, this will be trickier to get to behave the way you want in the Inspector.
     
  5. twilightZone

    twilightZone

    Joined:
    Oct 10, 2014
    Posts:
    30
    Thanks for your answers.

    I will explain a little more what I want to do
    I read this data from a database.
    I have about 1000 to 5000 objects.
    Each object are very simple
    - a short "name" always a short string ("arthur", "patrick", "zoe23", …)
    - a short "type" always a short string ("sleep", "dead", "cell", …)
    - a value that can be
    an integer 3
    a float number 3.1415
    a string "sdfqsdfqsdfafa"
    an array [10, 20, 30] (that can be number and/or string)
    an array of array [ 10, [20, 30, 40], 100] or [ [10, 20, 30], [100, 200, 300], [1000, 2000, 3000] ] (that can be number and/or string)

    example for one cell --> [{name:"arthur"},{type:"cell"},{value:[10, ["toto", [10,2]]] }]
    example for one cell --> [{name:"patrick"},{type:"dead"},{value: 52.4 }]
    All my database must be in a simple array of 1000 to 5000 elements

    Example for the first two elements
    [ [{name:"arthur"},{type:"cell"},{value:[10, ["toto", [10,2]]] }], [{name:"patrick"},{type:"dead"},{value: 52.4 }], .... ]

    I must be able to
    - find an object quickly by his name (all the names are differents)
    - When you find an object you can read its type
    - when you find an object, you can read and change its value

    With all this data, I will read and update the value of each objects (with formulas) and I will generate a graphics in 3D in real time.
    I do not want that the variables are editable in the inspector

    Thanks a lot
     
    Last edited: Dec 28, 2015
  6. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    As @Dantus mentioned - easiest way is probably to add a generic argument to the class

    Code (csharp):
    1.  
    2. public class Foo<T>
    3. {
    4.     public string Name { get; set; }
    5.     public string FooType { get; set; }
    6.     public T Value { get; set; }
    7. }
    8.  
    9. var f = new Foo<string>();
    10. var f1 = new Foo<int>();
    11. // etc etc
    12.  
     
  7. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    At first @KelsoMRK's answer seemed like the right answer, but you cannot have an array of generics with different types. (Actually, more to the point, you want a Dictionary rather than an array, but one problem at a time.)

    Just use an 'object'.
    Code (csharp):
    1. public class Foo
    2. {
    3. public string Name;
    4. public string fooType;
    5. public object Value;
    6. }
    7.  
    8. Foo f1 = new Foo();
    9. f1.Value = "foobar";
    10. if (f1.Value.GetType() == typeof(string) ) {
    11. //it's a string
    12. }
     
  8. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @StarManta, for me personally, type safety is an absolute must, whenever possible (I praise it like a cultural achievement). Instead of using object, I would take @KelsoMRK's code and make it serializable using a custom serializer (though I have never done that so far) or make some subclasses with the actual types, like:
    Code (csharp):
    1. public class FooString : Foo <string> {
    2. }
    Yes, of course, that means one array or dictionary is not enough, but it is type safe.
     
  9. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    Then it doesn't meet the requirements stated in the question.

    For a little more effort than simply using 'object', he could use inheritance. An abstract FooBase class with the name and type and an untyped Value accessor, and then derived classes for string, int, etc. An array of FooBase would store all of them.

    Code (csharp):
    1. public abstract class FooBase {
    2. public string Name;
    3. public string FooType;
    4. public abstract object GetValue();
    5. }
    6.  
    7. public class FooString : FooBase {
    8. public string stringValue;
    9. public override object GetValue() { return stringValue; }
    10. }
    11.  
    12. ...
    13.  
    14. FooBase[] fooArray = new FooBase[2];
    15. fooArray[0] = new FooString(...);
    16. fooArray[1] = new FooInt(...);
    17.  
    18. if (fooArray[1] is FooInt) {
    19. ( (FooInt)fooArray[1]).intValue = 1;
    20. }
     
  10. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I would wrap the whole collection and provide generic accessors. Something like:

    Code (CSharp):
    1. public UberCollection {
    2.     private Dictionary<string, object> theStuff;
    3.  
    4.     public T GetStuff <T> (string identifier){
    5.         return theStuff[identifier] as T;
    6.     }
    7. }
     
    Last edited: Dec 29, 2015
    StarManta likes this.
  11. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    That's a pretty good solution. Doesn't the declaration of the method need a 'T' return type though?
     
    Kiwasi likes this.
  12. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Fixed. :) This method still requires the caller to know what the type of the object is in advance.

    If you start to get to complicated I would suggest using an existing JSON or XML library.
     
  13. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    The downside to this is, of course, that passing the wrong argument in T could result in valid keys returning null because the cast failed.

    It would be a pain, but ultimately the safest solution is to provide all of the scenarios as members and simply let the unused ones be null. Otherwise, I would go with separate collections of a generic class for each possible type.
     
    Kiwasi likes this.
  14. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    True. You would probably want methods for checking the presence of a key, and for checking the type associated with a key.

    Rereading the OP it might still be better to use an existing JSON library. Seems to tick all of the boxes.
     
  15. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    I sort of thought that was a design feature. Wouldn't I WANT it to return null if I give it the wrong type? That way I can easily do null checks to determine what type it actually is and do logic based on that.
     
  16. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    I guess it really depends on the interpretation - which would require the context of the class at large. Does null mean the thing doesn't exist or that I gave it the wrong type? The fact that it's ambiguous probably isn't a great starting point in either case :)

    I guess you could return a boolean to indicate existence and return the thing as an out:
    Code (csharp):
    1.  
    2. public bool GetThing<T>(string key, out T theThing) { }
    3.  
    but at a certain point it sort of becomes a question of "how the hell am I supposed to even use this?"
     
    Kiwasi likes this.
  17. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    My assumption is the OP has some sort of sensible use case. ;)
     
  18. twilightZone

    twilightZone

    Joined:
    Oct 10, 2014
    Posts:
    30
    First of all, I want to thanks you for your help.
    I choose @StarManta method.
    For the value that I do not know, I use an object
    In the class, I have the ability to test if the 3 values are good.
    For example, for a "type" --> cell, you can not have a "value" integer and so on
    It is not possible that I have here (in the class) an error when creating a member.
    If I have an error, when I call the class, it is a big bug.
    What is the best way to show me the bug ?
    Is it a good idea to use THE UNITY ASSERTION LIBRARY ??
    http://blogs.unity3d.com/2015/08/25/the-unity-assertion-library/

    Thanks