如何在抽象类中定义的静态方法中获取当前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);
编辑:
以下是该方案。
实体代表一个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
中做到这一点?
答案 0 :(得分:10)
你基本上不能。
对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()
...
答案 1 :(得分:7)
静态方法在C#中不多态 - 子类无法覆盖此实现。
编辑:
基本上,正如Jon Skeet指出的那样,C#编译器会将对SubType.StaticMember
的调用视为等同于BaseType.StaticMember
(除非子类型提供 new ,隐藏具有相同名称的成员)。因此,此代码将始终在Identifier
类型的“上下文”中运行,并且无法改进:
Type currentType = typeof(Identifier);
就个人而言,我不喜欢C#甚至允许你通过'子类型访问静态成员 - 它只是设置了令人讨厌的错误和误解。
答案 2 :(得分:0)
最简单的方法是使用泛型:
[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中完成。
答案 3 :(得分:0)
C#
不支持静态成员的多态性。静态成员不能是虚拟的或包含在接口中。
因此,即使所有类都具有一些具有相同名称和签名的静态成员,也无法轻松地对类进行分组。