Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I access a constant from an object?

Tags:

c#

public class Foo
{
    public const int type = 1;
}

Why can't i do this? Is there a reason behind it or am I trying to access the constant in a wrong way?

new Foo().type;

I know I can do Foo.type but given my scenario, I cant do that. For example if I have two class which inherit from a base class like this:

public class Base
{
    ...
}

public class Foo : Base
{
    public const int type = 0;
}

public class Bar : Base
{
    public const int type = 1;
}

public static void printType(Base b)
{
     Console.WriteLine(b.type);
}

I would want to get the type property of the class sent through the printType() function but I cant since I can only access the type from the Class, not the object its self.

A work around would be to do

if(b is Foo){
    Console.Write(Foo.type);
}elseif....

but this seems stupid and not viable if you have many sub classes of Base


Solution

I ended up using readonly instead of const like this:

public readonly int type = 0;
like image 314
Krimson Avatar asked Dec 12 '22 02:12

Krimson


2 Answers

Yes, you're trying to access it in the wrong way. A constant isn't associated with an instance of a type - it's associated with the type itself. So you want:

int x = Foo.type;

Basically, const members are implicitly static, and C# doesn't let you access static members as if they were instance members, via a value. (Note that in .NET naming conventions, it should be Type rather than type.)

EDIT: Now that you've explained the actual situation, it appears you're trying to use polymorphism, which won't work for constants. So instead, you should have an abstract property in the base class, implemented in subclasses.

public abstract class Base
{
    public abstract int Type { get; }
}

public class Foo : Base
{
    public override int Type { get { return 0; } }
}

public class Bar : Base
{
    public override int Type { get { return 0; } }
}

Alternatively, just have a normal property in the base class which is populated via the base class constructor:

public class Base
{
    private readonly int type;
    public int Type { get { return type; } }

    protected Base(int type)
    {
        this.type = type;
    }
}

public class Foo : Base
{
    public Foo() : base(0) {}
}

public class Bar : Base
{
    public Bar() : base(1) {}
}
like image 145
Jon Skeet Avatar answered Jan 01 '23 19:01

Jon Skeet


If you just want something to identify the dynamic (most-derived) type of the object passed in, that's built into .NET, via the Object.GetType() method.

public static void printType(Base b)
{
     Console.WriteLine(b.GetType().Name);
}

Of course, this isn't quite the same as having attached data under your control. You can, however, use a Dictionary<Type, T> to associate data of arbitrary type with the various subclasses. It would be reasonable to use the subclass type initializer to install new entries into such a dictionary.

public class Base
{
    static internal readonly Dictionary<System.Type, int> TypeMap =
       new Dictionary<System.Type, int>();
}

public class Foo : Base
{
    static Foo { TypeMap.Add(typeof(Foo), 0); }
}

public class Bar : Base
{
    static Bar { TypeMap.Add(typeof(Bar), 1); }
}

public static void printType(Base b)
{
     Console.WriteLine(Base.TypeMap[b.GetType()]);
}

This WILL be a bit slower than the field-per-object method, however it doesn't add any extra storage per-object.

like image 29
Ben Voigt Avatar answered Jan 01 '23 18:01

Ben Voigt