How to store a reference to a static class?

25,641

Solution 1

Update: I am going to use my psychic powers to try and figure what I think you're trying to do.

I'm guessing you have a static class with some methods that you want to access from within another class. Is that right?

Something like this, in other words:

static class HelperMethods
{
    public static void SomeHelperMethod();
}

...and what you want to do is something like this?

class SomeOtherClass
{
    public void MethodThatUsesHelperMethod()
    {
        // You want to be able to have "Helper" mean "HelperMethods"?
        Helper.SomeHelperMethod();
    }
}

If I've interpreted you correctly, there's only one way (that I can think) to sort of accomplish what you're after. This would be to add a using declaration to effectively alias your static type:

// At top of file
using Helper = HelperMethods;

Note that if you do this, you're creating a file-wide alias. There's no way to alias classes at only the class level.


StaticClass is the name of the class. Your StaticProperty property expects an instance of the class, which will never exist because the class is static.

I'm actually surprised you can even have a property typed as a static class, since it represents a total impossibility. (Oh wait, you can't do that; that's what you were saying.)

You say you want to store a "reference to a static class"; I have to assume you mean that you want a reference to the Type object representing the class, in which case you should do this:

public Type StaticProperty { get; set; }

// ...

StaticProperty = typeof(StaticClass);

Solution 2

Static classes are both abstract and sealed (take a peek at the generated IL). So, you can't create an instance of it, and you can't subclass it to have instances of subclasses. That combination alone makes it impossible for you to ever have a reference to an instance of a static class.

Now, to have a reference to the static class work the way you want, you'd have to have metaclasses in C#, or some different kind of aliasing.

To achieve what you want today, you'd have to manually delegate all methods from a wrapper class to the desired static class, or abandon static typing and use dynamic:

public class StaticWrapper : DynamicObject {
  Type _type;
  public StaticWrapper(Type type) {
    _type = type;
  }
  public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
    var method = _type.GetMethod(binder.Name, BindingFlags.Static | BindingFlags.Public, null, args.Select(a => a.GetType()).ToArray(), null);
    if (method == null) return base.TryInvokeMember(binder, args, out result);
    result = method.Invoke(null, args);
    return true;
  }
  // also do properties ...
}

Usage:

public static class GenericStuff {
  public readonly dynamic LinearAlgebra = new StaticWrapper(typeof(LinearAlgebra));
  public readonly dynamic String = new StaticWrapper(typeof(StringUtilities));
  public readonly dynamic Geometry = new StaticWrapper(typeof(GeometryOps));
}

Solution 3

Section §8.7.12 of the C# specification reads:

Classes that are not intended to be instantiated, and which contain only static members should be declared as static classes. Examples of such classes are System.Console and System.Environment. Static classes are implicitly sealed and have no instance constructors. Static classes can be used only with the typeof operator and to access elements of the class. In particular, a static class cannot be used as the type of a variable or be used as a type argument

Because a static class has no constructors, you can't instantiate it. Because it is sealed you cannot subclass it and create an instance of a subclass. Even if you could subclass it you wouldn't be able to call the base constructor, and therefore you still couldn't instantiate it.

Since you cannot create an object of the type of a static class, it makes no sense to use it as a return type.

Since StaticClass is a type name, not an expression, you cannot pass it as a parameter (in your case, to the property setter). However, you can obtain an instance of the Type class that represents it with the expression typeof(StaticClass).

Solution 4

You cannot store a reference to a static class. You can only store references to instances, and there are no instances of static classes (although static classes may have instance members).

Solution 5

You should take another look at the MSDN page on static classes.

"A static class is basically the same as a non-static class, but there is one difference: a static class cannot be instantiated. In other words, you cannot use the new keyword to create a variable of the class type. Because there is no instance variable, you access the members of a static class by using the class name itself."

Share:
25,641
Joan Venge
Author by

Joan Venge

Professional hitman.

Updated on December 08, 2020

Comments

  • Joan Venge
    Joan Venge over 3 years

    So something like:

    public static class StaticClass {}
    
    public class InstanceClass
    {
        static StaticClass StaticProperty {get;set;}
    
        public InstanceClass()
        {
            InstanceClass.StaticProperty = StaticClass;
        }
    }
    

    I thought one could do this but the compiler returns these errors:

    static types cannot be used as parameters

    static types cannot be used as return types

    EDIT: I know that this doesn't work, but why? I imagine StaticClass is stored somewhere in memory, so other variables could be allowed to refer to it at the same memory, right?

    EDIT2: One of the use cases would be something like this:

    Say you have 5 different static classes you have collected with no source code, and they do generic stuff, so you want to have convenient access to them through a single static class. You could do it like:

    public static class GenericStuff
    {
        public LinearAlgebra LinearAlgebra {get;set;}
        public StringUtilities String {get;set;}
        public GeometryOps Geometry {get;set;}
    }
    

    And use it like:

    GenericStuff.LinearAlgebra.GetAngleBetweenVectors(v0, v1);
    

    Some other use cases you could think of.