C# GetType()会说谎吗?
基于几天前在SO中提出的以下问题:阅读答案,我开始思考,如果使C# GetType()会说谎吗?,c#,types,C#,Types,基于几天前在SO中提出的以下问题:阅读答案,我开始思考,如果使GetType()不是虚拟的,是否真的可以确保对象不能对其类型撒谎 具体而言,Eric的回答如下: 框架设计者不打算添加一个极其危险的特性,比如允许对象在其类型上撒谎,仅仅是为了使它与同一类型上的其他三种方法保持一致 现在的问题是:我能不能制造一个关于它的类型撒谎的对象,而不让它立即变得明显?我可能在这里犯了很大的错误,如果是这样的话,我想澄清一下,但是请考虑下面的代码: public interface IFoo { Typ
GetType()
不是虚拟的,是否真的可以确保对象不能对其类型撒谎
具体而言,Eric的回答如下:
框架设计者不打算添加一个极其危险的特性,比如允许对象在其类型上撒谎,仅仅是为了使它与同一类型上的其他三种方法保持一致
现在的问题是:我能不能制造一个关于它的类型撒谎的对象,而不让它立即变得明显?我可能在这里犯了很大的错误,如果是这样的话,我想澄清一下,但是请考虑下面的代码:
public interface IFoo
{
Type GetType();
}
public static void Main(string[] args)
{
IFoo badFoo = new BadFoo();
IFoo niceFoo = new NiceFoo();
PrintObjectType("BadFoo", badFoo);
PrintObjectType("NiceFoo", niceFoo);
PrintGenericType("BadFoo", badFoo);
PrintGenericType("NiceFoo", niceFoo);
}
public static void PrintObjectType(string actualName, object instance)
{
Console.WriteLine("Object {0} says he's a '{1}'", actualName, instance.GetType());
}
public static void PrintGenericType<T>(string actualName, T instance)
{
Console.WriteLine("Generic Type {0} says he's a '{1}'", actualName, instance.GetType());
}
以及所述接口的以下两种实现:
public class BadFoo : IFoo
{
Type IFoo.GetType()
{
return typeof(int);
}
}
public class NiceFoo : IFoo
{
}
然后,如果运行以下简单程序:
static void Main(string[] args)
{
IFoo badFoo = new BadFoo();
IFoo niceFoo = new NiceFoo();
Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString());
Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString());
Console.ReadLine();
}
果然badFoo
输出了一个错误的类型
现在我不知道这是否有任何严重的影响,Eric将这种行为描述为“极其危险的特性”,但这种模式会构成可信的威胁吗?据我所知,最糟糕的情况是误导碰巧使用有毒类的无辜程序员,例如:
Type type = myInstance.GetType();
string fullName = type.FullName;
string output;
if (fullName.Contains(".Web"))
{
output = "this is webby";
}
else if (fullName.Contains(".Customer"))
{
output = "this is customer related class";
}
else
{
output = "unknown class";
}
如果myInstance
是问题中描述的类的实例,它将被视为未知类型
所以我的答案是否定的,在这里看不到任何真正的威胁。有两种方法可以确定类型:
对不能重载的类型使用typeof
将实例强制转换为对象
,并调用GetType()
方法
object.GetType
和IFoo.GetType
之间存在差异GetType
在编译时在未知对象上调用,而不是在接口上调用。在您的示例中,对于outputbadFoo.GetType
,它应该是bahaviour,因为您重载了该方法。唯一的问题是,其他程序员可能会对这种行为感到困惑
但是如果您使用typeof()
它将输出类型相同,并且您不能覆盖typeof()
程序员还可以在编译时看到他调用的方法GetType
因此,对于您的问题:这种模式不能构成可信的威胁,但它也不是最好的编码方式。我认为不会,因为调用GetType的每个库代码都会将变量声明为“Object”或泛型类型“not”
以下代码:
public interface IFoo
{
Type GetType();
}
public static void Main(string[] args)
{
IFoo badFoo = new BadFoo();
IFoo niceFoo = new NiceFoo();
PrintObjectType("BadFoo", badFoo);
PrintObjectType("NiceFoo", niceFoo);
PrintGenericType("BadFoo", badFoo);
PrintGenericType("NiceFoo", niceFoo);
}
public static void PrintObjectType(string actualName, object instance)
{
Console.WriteLine("Object {0} says he's a '{1}'", actualName, instance.GetType());
}
public static void PrintGenericType<T>(string actualName, T instance)
{
Console.WriteLine("Generic Type {0} says he's a '{1}'", actualName, instance.GetType());
}
IFoo BadFoo说他是一个“System.Int32”
IFoo NiceFoo说他是一个“类型概念,NiceFoo”
问得好!在我看来,只有当GetType在对象上是虚拟的,而事实并非如此时,才能真正误导其他开发人员
您所做的类似于阴影GetType,如下所示:
public class BadFoo
{
public new Type GetType()
{
return typeof(int);
}
}
public void CheckIfInt(object ob)
{
if(ob.GetType() == typeof(int))
{
Console.WriteLine("got an int! Initiate destruction of Universe!");
}
else
{
Console.WriteLine("not an int");
}
}
有了这个类(并使用),您确实可以:
int n1 = 12;
BadFoo foo = new BadFoo();
Console.WriteLine("n1 and n2 are the same type: {0}",
Object.ReferenceEquals(n1.GetType(), foo.GetType()));
// output:
// n1 and n2 are the same type: True
那么,伊克斯,你成功地撒谎了,对吗?
嗯,是和否。。。将此作为一个漏洞将意味着使用BADFO实例作为对某个方法的一个参数,它可能是一个<>代码>对象< /代码>或一个对象层次结构的公共基类。大概是这样的:
public class BadFoo
{
public new Type GetType()
{
return typeof(int);
}
}
public void CheckIfInt(object ob)
{
if(ob.GetType() == typeof(int))
{
Console.WriteLine("got an int! Initiate destruction of Universe!");
}
else
{
Console.WriteLine("not an int");
}
}
但是CheckIfInt(foo)
打印“非整数”
因此,基本上(回到您的示例中),您只能使用有人针对您的IFoo
接口编写的代码来利用您的“说谎类型”,这一点非常明确,因为它有一个“自定义”的GetType()
方法
只有当GetType()是对象上的虚拟类型时,您才能创建一个“说谎”类型,该类型可以与上面的CheckIfInt
等方法一起使用,从而在其他人编写的库中造成严重破坏。如果您想安全地抵御这种黑客攻击,您有一些选择:
首先强制转换为对象
通过首先将实例强制转换为对象,可以调用原始的GetType()
方法:
Console.WriteLine("BadFoo says he's a '{0}'", ((object)badFoo).GetType());
结果:
BadFoo says he's a 'ConsoleApplication.BadFoo'
使用模板方法
使用此模板方法还将为您提供实际类型:
static Type GetType<T>(T obj)
{
return obj.GetType();
}
GetType(badFoo);
静态类型GetType(T obj)
{
返回obj.GetType();
}
GetType(badFoo);
不,你不能让GetType撒谎。你只是在介绍一种新方法。只有知道此方法的代码才会调用它
例如,您不能让第三方或框架代码调用新的GetType方法而不是真正的方法,因为该代码不知道您的方法存在,因此永远不会调用它
然而,这样的声明可能会让您自己的开发人员感到困惑。使用声明编译的任何代码,以及使用类型为IFoo的参数或变量的代码,或者从中派生的任何类型的代码,实际上都将使用新方法。但是,由于这只会影响您自己的代码,所以它并没有真正施加“威胁”
如果您确实希望为类提供自定义类型描述,那么应该使用,也许可以通过使用注释类来完成。这在某些情况下很有用。事实上,已经有一种类型可以存在于GetType
中:任何可为空的类型
:
输出True
实际上,说谎的不是int?
,而是隐式转换到对象
将int?
转换为一个装箱的int
。但无论如何,你不能用GetType()
从int
中分辨出int?
有趣的标题和主题IFoo.GetType
和object.GetType
不是一回事,所以除了糟糕的风格,这里没有什么不好的事情发生。编辑:通常对编译时未知的对象调用GetType
,在大多数情况下是object
而不是一些不可靠的接口。:)先生,你的头衔让我很高兴。你刚刚介绍了新成员,也叫GetType
,签名相同。这与重要的GetType
方法无关