如何从抽象类中的静态方法获得当前类型?

本文关键字:类型 静态方法 抽象类 | 更新日期: 2023-09-27 18:02:26

如何在抽象类中定义的静态方法中获得当前的Type ?

请注意,由于该方法是在抽象类中定义的,所以我不能使用typeof

我为什么要这样做?一个可能的用法是属性。考虑下面的例子:

[Identifier(1000)]
public class Rock : Entity { }
public abstract class Entity
{
    public static ushort Identifier
    {
        get
        {
            // How do I get here the current type of the object?
            Type currentType = ...;
            // in a non-static method or property, I'd do:
            // Type currentType = this.GetType();
            foreach (IdentifierAttribute attribute in currentType.GetCustomAttributes(true))
                return attribute.Identifier;
            throw new EntityException("No identifier has specified for this type of entity.");
        }
    }
}
Rock rock = new Rock();
// should print 1000
Console.WriteLine(rock.Identifier);
编辑:

场景如下。

Entity表示一个3D对象。我在写一个服务器软件,它有一个这样的实体列表。服务器手动序列化列表并将其发送给客户端。由于性能在这里非常重要,所以我没有发送类型名。每一种类型的实体都有一个唯一的标识符,所以当客户端获得数据时,它可以有效地反序列化它。

创建一个实体的实例,我这样做:

Entity entity = EntityRepository.Instance.CreateNew(identifier);

EntityRepository类是这样的:

public sealed class EntityRepository
{
    private static readonly Lazy<EntityRepository> lazy =
        new Lazy<EntityRepository>(() => new EntityRepository());
    IDictionary<ushort, Func<Entity>> _repo;
    private EntityRepository()
    {
        _repo = new Dictionary<ushort, Func<Entity>>();
    }
    public static EntityRepository Instance 
    { 
        get { return lazy.Value; } 
    }
    public Entity CreateNew(ushort id)
    {
        return _repo[id]();
    }
    public void Add<T>(ushort id)
        where T : Entity, new()
    {
        _repo.Add(id, new Func<Entity>(() =>
        {
            return new T();
        }));
    }
}

当前的Add<T>方法有一个表示标识符的参数。

但是我如何编写一个没有参数的Add<T>方法-自动识别标识符?

所以我在考虑添加一个属性到嵌套的Entity:

[Identifier(1000)]
public class Rock : Entity { }

和一个返回Identifier属性值的静态属性。

那么,一个没有参数的Add<T>方法看起来像这样:

public void Add<T>(ushort id)
    where T : Entity, new()
{
    _repo.Add(T.Identifier, new Func<Entity>(() =>
    {
        return new T();
    }));
}

注意,在本例中,我可以只执行T.GetType()来获取属性,但这不是重点。我怎么能做到这一点在静态属性,Entity.Identifier ?

如何从抽象类中的静态方法获得当前类型?

基本上不能。

Rock.Identifier的调用将被编译器解析为Entity.Identifier——根本没有任何上下文可以找到该类型。

rock.Identifier的调用甚至不会编译,因为您试图通过变量访问静态成员。

最好的解决方法将取决于真实的场景-在您发布的情况下,我建议在其他地方创建一个静态方法,接受类型作为参数。

实际上,您可以通过使用编译时类型Rock:

以一种非常可怕的方式为您的特定场景伪造它。
public static class NastyExtensions
{
    public static ushort GetIdentifier<T>(this T actualValueIsIgnored)
    {
        Type type = typeof(T);
        ... code as before
    }
}

:

Rock rock = new Rock();
Console.WriteLine(rock.GetIdentifier());

但是不是是多态的。例如:

Entity rock = new Rock();
Console.WriteLine(rock.GetIdentifier()); // Bang! T would be Entity here

您可以更改扩展方法为调用GetType()当然…

静态方法在c#中不是多态的——子类没有办法覆盖这个实现。

编辑:本质上,正如Jon Skeet指出的那样,c#编译器将把对SubType.StaticMember的调用视为等同于对BaseType.StaticMember的调用(当然,除非子类型提供了一个new,隐藏具有相同名称的成员)。因此,这段代码将始终在Identifier类型的"上下文中"运行,并且没有办法改进:

Type currentType = typeof(Identifier);

就我个人而言,我不喜欢c#甚至允许你"通过"子类型访问静态成员——它只会造成严重的错误和误解。

最简单的方法是使用泛型:

[Identifier(1000)]
public class Rock : Entity<Rock> { }
public abstract class Entity<T>
{
    public static ushort Identifier
    {
        get
        {
            // How do I get here the current type of the object?
            Type currentType = typeof(T);
            foreach (IdentifierAttribute attribute in currentType.GetCustomAttributes(true))
                return attribute.Identifier;
            throw new EntityException("No identifier has specified for this type of entity.");
        }
    }
}

这样当你调用Rock.Identifier时,编译器会将其解析为Entity<Rock>.Identifier。这个模式的一个例子是Castle ActiveRecord。

C#不支持静态成员的多态性。静态成员不能是虚的,也不能包含在接口中。因此,即使所有类都有一些具有相同名称和签名的静态成员,您也无法轻松地对类进行分组。