确定静态方法中的引用类型

时间:2014-05-27 03:14:50

标签: c# c#-2.0

我认为这可能是不可能的,但如果是,那就知道了。

我有一个静态维护它的子类实例的抽象类。我想在我的基类中实现一个静态getInstance()方法,该方法将获取引用的任何类的实例。所以我需要一种方法来告诉静态调用中引用了哪个类。

我认为代码会更清楚:

abstract class Base
{
    private static List<Base> allInstances;
    public static List<Base> AllInstances
    {
        get {
            if(allInstances==null)
            {
                // Implementation not relevant and not included to avoid clutter
            }
            return allInstances;
        }
    }
    public static Base getInstance()
    {
        Type callingType = // This is what I am trying to fill in
        if(callingType == typeof(Base))
            throw new InvalidOperationException("Cannot get instance of Base class");
        return AllInstances.Find(i => i.GetType() == callingType);
    }
}


class A:Base { }
class B:Base { }

因此,如果我致电A.getInstance()我的callingType变量将为typeof(A)。我的主要目标是避免在我的代码中调用Find来使其更清晰,更易读,但我也很好奇,如果可能的话。

3 个答案:

答案 0 :(得分:1)

C#不支持虚拟静态方法。

一种解决方法是使用GetInstance()的通用方法。呼叫者不会呼叫A.GetInstance(),而是呼叫Base.GetInstance<A>()。然而,效果是一样的:

abstract class Base
{
...
  public static T getInstance<T>() where T : Base
  {
    Type callingType = typeof(T);
    // no need to check type; T will always be a type of or derived from Base
    return AllInstances.Find(i => i.GetType() == callingType) as T;
  }
}

虽然它会涉及一些样板文件,但您可以(如果您选择)在派生类级别编写便捷方法以获得相同的效果:

class A:Base 
{
    public static A getInstance() {return Base.getInstance<A>();}
}
class B:Base
{
    public static B getInstance() {return Base.getInstance<B>();}
}

答案 1 :(得分:1)

不继承静态方法。他们是他们班级的范围。你写它的方式在A或B上没有“getInstance”方法......只在Base上。因此,通过您的方法,您尝试做的事情是不可能的。

但是,您可以使用通用方法:

public static T GetInstance<T>() where T : Base {
    return (T)AllInstances.Find(i => i.GetType() == typeof(T));
}

然后你可以只请求像这样的类型的实例

var a = Base.GetInstance<A>();
var b = Base.GetInstance<B>();

一样简单
var a = A.getInstance();
var b = B.getInstance();

因为类型T仅限于继承base(通过T:Base)的类型,所以你不必担心其他类型的类,因为它甚至不会编译:

var x = Base.GetInstance<SomeOtherRandomClass>();

答案 2 :(得分:1)

扩展我上面的评论,如果不将代码放在所有派生类中,你就无法真正做到。部分原因是,虽然您可以访问A.getInstance()B.getInstance(),但它们都会被编译到调用Base.getInstance()。参见IL的简单方法,例如:

public static void CallGetInstance()
{
    var a = A.getInstance();
    var b = B.getInstance();
    Console.WriteLine(a == b);
}

编译为:

.method private hidebysig static
    void CallGetInstance () cil managed
{
    // Method begins at RVA 0x2054
    // Code size 24 (0x18)
    .maxstack 2
    .locals init (
        [0] class TestIL.Base a,
        [1] class TestIL.Base b
    )

    IL_0000: nop
    IL_0001: call class TestIL.Base TestIL.Base::getInstance()
    IL_0006: stloc.0
    IL_0007: call class TestIL.Base TestIL.Base::getInstance()
    IL_000c: stloc.1
    IL_000d: ldloc.0
    IL_000e: ldloc.1
    IL_000f: ceq
    IL_0011: call void [mscorlib]System.Console::WriteLine(bool)
    IL_0016: nop
    IL_0017: ret
} // end of method Program::CallGetInstance

请注意,没有提到A.getInstanceB.getInstance。事实上,他们并不存在于IL中。由于StackFrameA.getInstance()的IL中没有方法,因此B.getInstance()和非常有用的技巧会有所帮助。

其他答案使用每个派生类调用的泛型方法提出了一种解决方法。这就像它将要获得的一样简单。