Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Require a "static" field in a derived class

I have a class hierarchy that represents a JSON based API. There is a generic factory that calls and deserializes the api into classes using .NET 4 (no 3rd party libs). I am trying to avoid having to instantiate the class to retrieve a read-only piece of information that is unique to each class.

I had thought (until I started reading this and this, ...) I would associate a static URL with a base class/interface and then set it in the derived class's constructor. Something like (this example will not work):

abstract class url {
  public abstract static string URL; // This is invalid syntax!
}

class b : url {
  static b () { URL = "http://www.example.com/api/x/?y=1"; }
}

class c: url {
  static c () { URL = "http://www.example.com/api/z"; }
}

// ... so the factory can do something like ...
b result = doJSONRequest<b>(b.URL);

This doesn't work. The static field can't be abstract, nor can it be uniquely set in b and c as the static variable is stored in the class it is defined in (url in this case).

How can I have a read only item associated with a class such that you can access the item (etc.) without having to instantiate the class?

like image 649
AlG Avatar asked Dec 18 '12 17:12

AlG


2 Answers

I've implemented a pattern like this to help remind me of constants that I need to setup per derived class that need to be statically accessible:

public abstract class Foo
{
    public abstract string Bar { get; }
}

public class Derived : Foo
{
    public const string Constant = "value";
    public override string Bar
    {
        get { return Derived.Constant; }
    }
}

I've even found that after implementing this pattern that the polymorphic use of the constant to be just as helpful.

like image 118
JG in SD Avatar answered Oct 03 '22 13:10

JG in SD


I understand you don't want to have to ask a instance but keep the method static. This is impossible, static field is loaded once in a module, and cannot be inherited.
I think the only way is to store a dictionary in a helper class, with the type as a key. Like this

class Helper
{
    static Dictionary<Type,string> _urls;
    public static string GetUrl(Type ofType)
    {
        return _urls[ofType];
    }

    public static void AddUrl(Type ofType, string url)
    {
        _urls.Add(ofType,url);
    }
}
class b
{
    static b(){ Helper.AddUrl(typeof(b),"  ");}
}
class Program
{
    b result= doJSONRequest<b>(Helper.GetUrl(typeof(b));
}

Or you can decorate the desired types with a custom attribute and store the data in that attribute. Like this

class UrlAttribute:Attribute
{
    public string Url{get;private set;}
    public UrlAttribute(string url){Url=url;}
}
[Url("someurl")]
class b { }
class Program
{
    void Main()
    {
        UrlAttribute attr = (UrlAttribute)Attribute.GetCustomAttribute(typeof(b), typeof(UrlAttribute));
        //in dot net 4.5 you can ask the type itself
        UrlAttribute attr = (UrlAttribute)typeof(b).GetCustomAttribute(typeof(UrlAttribute));
        //now you can write that...
        b result = doJSONRequest<b>(attr.Url);
    }
    //or even you can do that in doJSONRequest itself
    public T doJSONRequest<T>()
    {
         UrlAttribute attr = (UrlAttribute)typeof(T).GetCustomAttribute(typeof(UrlAttribute));
        ...
        //call it: b result=doJSONRequest<b>();
    } 
}

Of course you can pass on them all by reflection and initialize a dictionary, see this question.

like image 40
RoadBump Avatar answered Oct 03 '22 14:10

RoadBump