Here's我的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
ISampleInterface a = new A();
ISampleInterface b = new B();
a.SampleMethod();
b.SampleMethod();
//Console.WriteLine(a.myValue); // can't do it!! a is not A
Console.WriteLine(a.GetType()); // uhm...
}
}
interface ISampleInterface
{
void SampleMethod();
}
class A : ISampleInterface
{
public double myValue = 10.0;
public void SampleMethod() {
Console.WriteLine("A");
}
}
class B : ISampleInterface
{
public double myValue = 20.0;
public void SampleMethod() {
Console.WriteLine("B");
}
}
}
我通过接口初始化一个类(由类实现)。
显然,无法访问a.myValue
,因为正确的Rextester.ISampleInterface
不包含这样的定义。
但是如果我问编译器哪个类型是a
,它会输出Rextester.A
(我相信不是这样)。
为什么?更重要的是,哪种类是a
?一种受其界面限制的混合切片类?不确定我将如何定义它...
您可以调用哪些方法(在reflection / dynamic
之外)基于变量的编译时类型。
引用转换(它是对它实现的接口的现有引用的内容)不会改变对象的类型。但是,如果您将该转换的结果存储在变量中,则变量的类型才是最重要的。
在.NET世界中,没有什么能比得上C ++的切片(我认为你所指的是切片),我能想到 - 当然你不会从编写简单的代码中得到它。
声明为接口类型的变量永远不会包含对“仅”接口的引用。它将始终是某个特定具体结构/类类型的对象。
但是,如果我问编译器哪个类型是
a
,它输出Rextester.A
(我不相信)
如果通过“询问编译器”你的意思是调用a.GetType()
,那不是你正在做的事情。您要求运行时获取a
引用的对象的实际类型。运行时正确地告诉你它是一个Rextester.A
。
另一方面,编译器不知道这一点。该变量被声明为ISampleInterface
,因此所有编译器都可以安全地执行绑定到接口定义的方法。
如果将变量强制转换为A
,则可以访问其成员:
A newA = a;
newA.myValue = 15; // perfectly valid
请注意,a
引用的实际对象没有改变(意味着它是同一个对象 - 显然你改变了它的一个成员字段)。您仍然可以通过a
或类通过newA
引用作为接口。
如果您曾向编译器询问a
的类型,但使用如下方法:
public Type GetCompileTimeType<T>(T inputObject)
{
return typeof(T);
}
(信用卡qsxswpoi)
并打电话
this answer
你会得到Console.WriteLine(GetCompileTimeType(a));
Rextester.ISampleInterface
无法访问,因为它的范围为a.myValue
ISampleInterface
正确地导致a.GetType()
,因为这在运行时被解析为分配给A
的类型的实例,即a
。它仅在A
的范围内。
例如...
ISampleInterface
您正在创建一个声明为ISampleInterface a = new A();
的A
实例。
ISampleInterface
您可以访问声明的内容。
a.SampleMethod();
您无法访问未声明的内容。
Console.WriteLine(a.myValue);
Console.WriteLine(a.GetType());
可以从GetType
调用,它可以自然地扩展,所以你可以调用它,因为它是从一个隐式基类型声明的。在这种情况下,System.Object
返回GetType
,因为这正是A
的意思; a
的一个例子。