2

I've found a lot of similar topics on this but not one that answers my question directly. I'm making a game which involves placing different types of rooms. I have a Room class, then several rooms which inherit from this, e.g. Bedroom, Canteen, etc.

Each room has certain static parameters to set its attributes. For example:

public class Room : WorldEntity
{
    public static string Name = "Room";
    public static uint MinHeight = 0;
    public static uint MinWidth = 0;
    //...
}

public class Bedroom : Room
{
    new public static string Name = "Bedroom";
    new public static uint MinHeight = 4;
    new public static uint MinWidth = 4;  
     //...
}

When creating the room, I first pass through the type of the required room, e.g.

public static void PlaceRoom(Type T){//begin room creation process}

What I want to know is, how can I get the attributes of T from within my PlaceRoom function? For example, how can I get T.MinHeight (which will return 4 when T is type Bedroom)? Or is there a better way to go about this?

I wasn't intending to initialise my class T (where T : Room) until later, so that's why the members were static and I'm trying to use generics.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
Haighstrom
  • 577
  • 5
  • 16
  • Side note: avoid adding thankyou notes/signature to the post as they usually don't add useful in formation to the post. Edit you user information and upvote/accept/comment answers instead. – Alexei Levenkov Dec 05 '12 at 19:47
  • You are not, in fact, using generics. (naming a `Type` variable `T` is not it) – Kirk Woll Dec 05 '12 at 19:48
  • Passing around a type does not let you inspect a particular class for static members (unless you use reflection). See http://stackoverflow.com/questions/451453/how-to-get-a-static-property-with-reflection – SPFiredrake Dec 05 '12 at 20:04
  • possible duplicate of [How to access static methods of generic types](http://stackoverflow.com/questions/9146533/how-to-access-static-methods-of-generic-types) – Kate Gregory Dec 06 '12 at 02:46

3 Answers3

3

One option would be to create an IRoom interface that would define those values as properties. Each class would implement those properties and return a hard-coded result.

Another option would be to create one or more attributes and apply them to your classes. The PlaceRoom function would use reflection to read the attributes.

Jon B
  • 51,025
  • 31
  • 133
  • 161
  • 1
    Note that with the interface option you'll also have to construct an instance of the type to get the info out. – Servy Dec 05 '12 at 19:56
  • If I go down the Interface route, then I have to instantiate the class. If I was to do that, I could make this trivial by making the members non-static. Could someone post an example of reflection code? – Haighstrom Dec 05 '12 at 20:03
  • @user1880201 if you need these values without instantiating the class, then the attribute route would be a better choice. – Jon B Dec 05 '12 at 20:04
  • I don't know about attributes or reflection. Could you post some example code or a link to some? – Haighstrom Dec 05 '12 at 20:07
  • @Haighstrom - here is a tutorial: http://msdn.microsoft.com/en-us/library/aa288454(v=vs.71).aspx – Jon B Dec 05 '12 at 20:08
1

First of all you created public static fields which is very bad design. Public static fields should be readonly. Since you cannot make static fields / properties virtual and you don't want to create an instance before calling PlaceRoom you could use attributes to annotate your types:

class Program
{
    static void Main(string[] args)
    {
        PlaceRoom<Room>();
        Console.ReadKey(true);
    }

    public static void PlaceRoom<T>()
        where T : Room
    {
        string name = ((NameAttribute)typeof(T).GetCustomAttributes(false).First(x => x is NameAttribute)).Name;

        Console.WriteLine(name);
    }
}

[Name("Room")]
public class Room
{
}

[Name("Bedroom")]
public class Bedroom : Room
{
}

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class NameAttribute : Attribute
{
    public string Name { get; set; }

    public NameAttribute(string name)
    {
        Name = name;
    }
}
Adam Kostecki
  • 301
  • 1
  • 3
0

If you're always overriding (or new-ing) the properties and never actually placing an actual Room type, you can make both Room and all it's properties abstract, then just have your method signature be public static void PlaceRoom<T>(T room) where T : Room and be properly generic about it. Then let your Bedroom, Bathroom and whatnot inherit from Room.

If you will be adding new properties, this is just logically flawed as you cannot be generic about things that aren't actually generic.

Arve Systad
  • 5,471
  • 1
  • 32
  • 58