How to store a reference to a static class?
Asked Answered
S

11

15

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.

Spurn answered 4/3, 2011 at 1:7 Comment(3)
Can you explain how you were planning to use the property if you could do what you wrote?Decadent
I think what you're looking for is the metaclass. Unfortunately, this concept does not exist in C#.Bema
I know your pain. I am trying to do the same thing, as it would allow me to use a static class to define constants in server side C# and access these constants in Razor code, without duplicating them in JavaScript.Psychosis
A
21

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);
Anoint answered 4/3, 2011 at 1:12 Comment(9)
No I want to store a reference to the StaticClass, kind of like aliasing in this case to do StaticProperty.Method.Spurn
@Joan: What do you know, my psychic powers were right (see my update)! ;)Anoint
Thanks, you are right, that's what I want to do, but not a file level but class level, which you addressed. But why is that not allowed, surely using is doing this, and it could be allowed in other forms too.Spurn
@Joan: The using alias directive is a compile-time gimmick. Since you want to store the "alias" in a property you need a runtime representation of a type: Type objects. But you're might be better off with an interface definition and good old instances (you can make them singletons if you feel like it).Decadent
Thanks, also the reason I asked for this is, I know other languages that have similar static class semantics but allow "aliasing" at any level, and in any form. They also don't instance the static classes, so thought for C# this must be avoided on purpose, maybe because it was thought to be not very practical or the cost outweighed the benefits, etc.Spurn
@Joan: I bet those languages do some kind of auto-singleton magic behind the scenes. Btw can you name some? (Ruby?)Decadent
@Martinho: You might be right. I am not language expert. These are mostly less popular domain specific languages. But I think I have seen it in Ruby too.Spurn
@Joan: In Ruby each class is an object of type Class. That's why you can assign a class to a variable in Ruby. The main differences to C# are: 1) in Ruby you can get the object that represents a class with just the class name, while in C# you need to use typeof 2) in Ruby, being a dynamic language calling methods dynamically is easy. In C# you need to use reflection, or dynamic in v4.Decadent
You are tricky! This also seems to work for static declarations referencing another static class.Shana
H
7

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));
}
Hofmann answered 5/3, 2011 at 16:20 Comment(1)
I like your rather inventive answer!Psychosis
D
6

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).

Decadent answered 4/3, 2011 at 1:12 Comment(0)
T
3

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).

Turki answered 4/3, 2011 at 1:12 Comment(0)
L
1

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."

Landpoor answered 4/3, 2011 at 1:10 Comment(5)
Yes but I am not trying to create an instance, just trying to store the reference of it.Spurn
@Joan - There can be no references to it because there are no instances of it.Landpoor
By reference I don't necessarily mean .NET or C# reference but sort of like an alias, and alias that refers to my Static class.Spurn
@Landpoor Wouldn't there be one instance of it, created when the program was loaded?Rozella
@Landpoor There is in fact an instance of each static class in memory. It's a private instance. And C# could expose the ability to get a reference to each static class.Suave
A
1

I think this is what you are trying to say:

Ok, if you don't want to instantiate it, then your C# needs a bit more tweaking. Assuming your static class implements a property and/or method

public static class StaticClass
{
    public static string StaticProperty {get; private set; }

    public static void StaticMethod() { //DoSomething }
}

You can forward the property and function definitions in the InstanceClass, notice that you must prefix the class name of the static to the methods/properties that you want to call.

public class InstanceClass
{
   private string StaticProperty
   {
         get { return StaticClass.StaticProperty; }
   }

   private StaticMethod()
   {
        StaticClass.StaticMethod();
   }

   public InstanceClass()
   { }
}

I think that using InstanceClass as a wrapper like this is a bit complicated, and unecessary. I've found that its worth trying to minimize the need for static classes and methods in a codebase. They cause all sorts of headaches when trying to test and debug.

Alika answered 4/3, 2011 at 1:14 Comment(5)
No not trying to create an instance of StaticClass, but a reference to it (not in the C# terminology).Spurn
Thanks, yeah if I do that, then I have to provide a separate member for each method I need to expose.Spurn
Right. I think the occasional utility class is ok as static, but if you find yourself passing the same argument to every function...its not static.Alika
I agree Ritch or if you have some global singleton style type I also use static. Say like FileManager.Spurn
I don't believe in singletons either. Trivial factories and newing up types. I'd ban the static keyword if I could. Its nothing but trouble.Alika
B
1

I believe using the namespace feature would be the best way to accomplish what you're trying to do.

LinearAlgebra.cs

namespace GenericStuff
{
    public static class LinearAlgebra
    {
        public static TypeOfResult Function() { ... }
    }
}

Strings.cs

namespace GenericStuff
{
    public static class Strings
    {
        public static TypeOfResult Function() { ... }
    }
}

Geometry.cs

namespace GenericStuff
{
    public static class Geometry
    {
        public static TypeOfResult Function() { ... }
    }
}

All of which can be invoked starting with GenericStuff

var s = GenericStuff.Strings.Random(7);
var identity = GenericStuff.LinearAlgebra.Identity(3);
var square = GenericStuff.Geometry.Square(5);
var area = square.Area();
Blasphemous answered 7/12, 2015 at 19:54 Comment(0)
H
0

You can't do this. A class is not an instance of itself. "Dog" is not a Dog. You could assign typeof(StaticClass) to a field of type Type:

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

This lets you use reflection on the type.

Hellcat answered 4/3, 2011 at 1:12 Comment(1)
A class is not an instance of itself, but there is one instance of every static class. Everything is an object.Psychosis
R
0

What I believe the op wants is a way to access other classes easily via a "proxy" that you know of.

So, lets say you have a class called MapHelpers:

public class MapHelper
{
            public static string CalculateNearLocation (Vector3 position){...}
}

And you have many other "Helpers" that you don't really remember and just want to have them easily accessible. And so, you want to "store" them inside your "Helpers" class, just so you can remember where you put them.

You can either do this :

public class Helpers
{
  public class MapHelpers : MapHelper{}
}

And be able to access your MapHelper via :

Helpers.MapHelpers.CalculateNearLocation(pos)

Or do this :

public partial class Helpers
{
}

public partial class Helpers
{
     public class MapHelper
     {
            public static string CalculateNearLocation (Vector3 position){...}
     }
}

And be able to access it via :

Helpers.MapHelper.CalculateNearLocation(pos)

However, the first method, will give you a warning on your IDE (if you have that set) about accessing static methods via derived type.

Reiterant answered 30/9, 2014 at 16:38 Comment(0)
C
0

Depends on what you want to achieve in the end.

If you want to just change one class but not on runtime but on compile time (i.e. the same version of static file is going to be used), then you can easily just configure your app or just make several versions of the same file with various implementations.

Such approach is useful for e.g. translations if you have them in a static files.

Catrinacatriona answered 10/10, 2022 at 16:16 Comment(0)
L
0

This should be a comment, but I can't post code samples in comments, so, here goes - I just tried to do this:

    var view = MudClient.View;
    view.Main = this;
    view.Login = new Login();
    view.Register = new Register();

MudClient.View is a View is a static class member of type MudClientViewElements. This didn't work. The local view variable became a copy or something, not a reference, so MudClient.View.Main was not updated by this code, and remained null and caused a null reference exception later on. So to update the attributes of some static thing, you actually have to have..

My.Long.Fully.Qualified.Thing.Attribute = someValue;

.. on every line. I tried various forms of "using" to no avail. This appears to me to be a C#-ism designed protect programmers from themselves by not allowing them to proliferate references to global things and maybe discourage the use of globals or something. Personally, I think it's far more annoying than helpful, but mine may be the minority view.

Lancastrian answered 28/5, 2024 at 22:1 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.