在非静态方法中,我可以使用this.GetType()
获取Type
。那么在静态方法中如何获取相同的Type
呢?当然,我不能只写typeof(ThisTypeName)
,因为ThisTypeName
只有在运行时才知道。谢谢!
在非静态方法中,我可以使用this.GetType()
获取Type
。那么在静态方法中如何获取相同的Type
呢?当然,我不能只写typeof(ThisTypeName)
,因为ThisTypeName
只有在运行时才知道。谢谢!
this.GetType()
的一行代码,请尝试以下内容。Type t = MethodBase.GetCurrentMethod().DeclaringType
typeof(TheTypeName)
更昂贵。typeof(TheTypeName)
。 - Nyerguds其他答案没有完全阐明的一点是,这与您关于类型仅在执行时可用的想法相关。
如果使用派生类型来执行静态成员,则二进制中省略了实际类型名称。所以例如编译此代码:
UnicodeEncoding.GetEncoding(0);
现在用ildasm打开它...你会看到调用是这样发出的:
IL_0002: call class [mscorlib]System.Text.Encoding
[mscorlib]System.Text.Encoding::GetEncoding(int32)
编译器已解决对Encoding.GetEncoding
的调用-不再存在UnicodeEncoding
的痕迹。恐怕这使得您对“当前类型”的想法变得毫无意义。另一种解决方案是使用自引用类型。
//My base class
//I add a type to my base class use that in the
//static method to check the type of the caller.
public class Parent<TSelfReferenceType>
{
public static Type GetType()
{
return typeof(TSelfReferenceType);
}
}
然后在继承它的类中,我创建了一个自引用类型:
public class Child: Parent<Child>
{
}
现在,Parent类中的typeof(TSelfReferenceType)
调用将获取并返回调用方的Type
,而无需实例。
Child.GetType();
在静态方法中无法使用this
,因此直接这样做是不可能的。但是,如果您需要某个对象的类型,请调用GetType
并将this
实例作为必须传递的参数,例如:
public class Car {
public static void Drive(Car c) {
Console.WriteLine("Driving a {0}", c.GetType());
}
}
public class Car {
public void Drive() { // Remove parameter; doesn't need to be static.
Console.WriteLine("Driving a {0}", this.GetType());
}
}
我不明白为什么你不能使用typeof(ThisTypeName)。如果这是一个非泛型类型,那么应该可以使用:
class Foo {
static void Method1 () {
Type t = typeof (Foo); // Can just hard code this
}
}
class Foo<T> {
static void Method1 () {
Type t = typeof (Foo<T>);
}
}
我有没有漏掉什么显而易见的东西?
对于我的目的,我喜欢@T-moty的想法。尽管我多年来一直使用“自引用类型”信息,但稍后引用基类更难。
例如(使用@Rob Leclerc上面的例子):
public class ChildA: Parent<ChildA>
{
}
public class ChildB: Parent<ChildB>
{
}
public Parent<???> GetParent() {}
或者类型转换时呢?
var c = (Parent<???>) GetSomeParent();
所以,我尽可能避免使用它,并在必要时使用它。如果你必须使用它,我建议你遵循这个模式:
class BaseClass
{
// All non-derived class methods goes here...
// For example:
public int Id { get; private set; }
public string Name { get; private set; }
public void Run() {}
}
class BaseClass<TSelfReferenceType> : BaseClass
{
// All derived class methods goes here...
// For example:
public TSelfReferenceType Foo() {}
public void Bar(TSelfRefenceType obj) {}
}
现在你可以更轻松地使用BaseClass
了。然而,有时候,比如我的当前情况,从基类中公开派生类并不是必要的,使用@M-moty的建议可能是正确的方法。
然而,只有当基类在调用堆栈中不包含任何实例构造函数时,才能使用@M-moty的代码。不幸的是,我的基类确实使用实例构造函数。
因此,这里是我的扩展方法,考虑到基类的“实例”构造函数:
public static class TypeExtensions
{
public static Type GetDrivedType(this Type type, int maxSearchDepth = 10)
{
if (maxSearchDepth < 0)
throw new ArgumentOutOfRangeException(nameof(maxSearchDepth), "Must be greater than 0.");
const int skipFrames = 2; // Skip the call to self, skip the call to the static Ctor.
var stack = new StackTrace();
var maxCount = Math.Min(maxSearchDepth + skipFrames + 1, stack.FrameCount);
var frame = skipFrames;
// Skip all the base class 'instance' ctor calls.
//
while (frame < maxCount)
{
var method = stack.GetFrame(frame).GetMethod();
var declaringType = method.DeclaringType;
if (type.IsAssignableFrom(declaringType))
return declaringType;
frame++;
}
return null;
}
}
当您的成员是静态的时,您总是可以在运行时知道它属于哪种类型。在这种情况下:
class A
{
public static int GetInt(){}
}
class B : A {}
你不能调用(编辑:显然,你可以,见下面的评论,但你仍然会调用到A):
B.GetInt();
由于该成员是静态的,因此在继承情况下不起作用。因此,您始终知道类型为A。
编辑 这些方法仅在您将PDB文件与可执行文件/库一起部署时才有效,正如markmnl向我指出的那样。
否则,检测到问题可能会是一个巨大的问题:在开发中运行良好,但在生产中可能不行。
实用方法,只需在代码的任何位置调用该方法:
public static Type GetType()
{
var stack = new System.Diagnostics.StackTrace();
if (stack.FrameCount < 2)
return null;
return (stack.GetFrame(1).GetMethod() as System.Reflection.MethodInfo).DeclaringType;
}