如何存储对静态类的引用?

时间:2011-03-04 01:07:46

标签: c# .net compiler-construction

类似于:

public static class StaticClass {}

public class InstanceClass
{
    static StaticClass StaticProperty {get;set;}

    public InstanceClass()
    {
        InstanceClass.StaticProperty = StaticClass;
    }
}

我认为可以做到这一点,但编译器会返回这些错误:

  

静态类型不能用作参数

     

静态类型不能用作返回类型

编辑:我知道这不起作用,但为什么呢?我想StaticClass存储在内存中的某个地方,所以可以允许其他变量在同一个内存中引用它,对吗?

EDIT2:其中一个用例是这样的:

假设您收集了5个不同的静态类而没有源代码,并且它们执行通用的东西,因此您希望通过单个静态类方便地访问它们。你可以这样做:

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

并使用它:

GenericStuff.LinearAlgebra.GetAngleBetweenVectors(v0, v1);

您可以想到的其他一些用例。

9 个答案:

答案 0 :(得分:18)

更新:我将利用我的心灵力量来尝试计算我认为你尝试做什么。

我猜你有一个静态类,你想从另一个类中访问一些方法。是吗?

这样的东西,换句话说:

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

......你想做的是这样的事情吗?

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

如果我已经正确地解释了你,只有一种方式(我能想到)那种完成你所追求的目标。这将是添加using声明以有效地为您的静态类型设置别名:

// At top of file
using Helper = HelperMethods;

请注意,如果执行此操作,则表示您正在创建文件范围的别名。没有办法只在类级别别名。


StaticClass是该类的名称。您的StaticProperty属性需要该类的实例,该类将永远不存在,因为该类为static

我真的很惊讶你甚至可以把一个属性输入为静态类,因为它代表了一种完全不可能。(哦等等,你不能做那就是你所说的。)

你说你想存储一个“静态类的引用”;我必须假设你想要引用代表类的Type对象,在这种情况下你应该这样做:

public Type StaticProperty { get; set; }

// ...

StaticProperty = typeof(StaticClass);

答案 1 :(得分:7)

静态类都是抽象密封(看一下生成的IL)。因此,您无法创建它的实例,也无法将其子类化为具有子类的实例。仅凭这种组合使您无法获得对静态类实例的引用。

现在,要以您想要的方式引用静态类,您必须在C#中使用metaclasses,或者使用某种不同的别名。

要实现您今天所需的目标,您必须手动将所有方法从包装类委托给所需的静态类,或者放弃静态类型并使用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 ...
}

用法:

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));
}

答案 2 :(得分:5)

C#规范的§8.7.12部分为:

  

不打算成为的类   实例化,仅包含   静态成员应声明为   静态类。这样的例子   课程是System.Console和   System.Environment。静态类   是隐含的密封,没有   实例构造函数。静态类   只能与typeof一起使用   运算符和访问元素   类。特别是一个静态类   不能用作a的类型   变量或用作类型参数

因为静态类没有构造函数,所以无法实例化它。因为它是密封的,所以不能将其子类化并创建子类的实例。即使你可以继承它,你也无法调用基础构造函数,因此你仍然无法实例化它。

由于无法创建静态类类型的对象,因此将其用作返回类型是没有意义的。

由于StaticClasstype name,而不是expression,因此您无法将其作为参数(在您的情况下,传递给属性设置器)传递。但是,您可以使用表达式typeof(StaticClass)获取表示它的Type类的实例。

答案 3 :(得分:3)

您无法存储对静态类的引用。您只能存储对实例的引用,并且没有静态类的实例(尽管静态类可能包含实例成员)。

答案 4 :(得分:1)

答案 5 :(得分:1)

我认为这就是你想说的:

好的,如果您不想实例化它,那么您的C#需要更多调整。假设您的静态类实现了属性和/或方法

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

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

您可以在InstanceClass中转发属性和函数定义,请注意您必须将static的类名前缀添加到要调用的方法/属性中。

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

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

   public InstanceClass()
   { }
}

我认为使用InstanceClass作为这样的包装器有点复杂,而且不必要。我发现值得尝试最小化代码库中对静态类和方法的需求。在尝试测试和调试时,它们会引起各种各样的麻烦。

答案 6 :(得分:0)

你不能这样做。一个类不是它自己的一个实例。 “狗”不是狗。您可以将typeof(StaticClass)分配给Type:

类型的字段
static StaticClass StaticProperty {get; set}
InstanceClass.StaticProperty = typeof(StaticClass);

这使您可以对类型使用反射。

答案 7 :(得分:0)

我认为操作系统想要的是一种通过"代理"轻松访问其他课程的方法。你知道的。

所以,假设您有一个名为MapHelpers的类:

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

你还有很多其他的帮助"你真的不记得,只是想让它们易于访问。所以,你想要"存储"他们在你的"助手"上课,这样你才能记住你把它们放在哪里。

你可以这样做:

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

并且可以通过以下方式访问您的MapHelper:

Helpers.MapHelpers.CalculateNearLocation(pos)

或者这样做:

public partial class Helpers
{
}

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

并且可以通过以下方式访问它:

Helpers.MapHelper.CalculateNearLocation(pos)

但是,第一种方法会在IDE上给出一个警告(如果你有那套),关于通过派生类型访问静态方法。

答案 8 :(得分:0)

我相信使用命名空间功能将是完成您尝试的最佳方式。

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() { ... }
    }
}

所有这些都可以从GenericStuff

开始调用
var s = GenericStuff.Strings.Random(7);
var identity = GenericStuff.LinearAlgebra.Identity(3);
var square = GenericStuff.Geometry.Square(5);
var area = square.Area();