通用方法如何知道无法访问的类型?(或"我如何失去一美元")

Phi*_*ler 4 c# generics casting

所以,我们对我们的团队有一点赌注是否有效.我输了.这是代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using MyNamespace;

namespace PrivateGeneric
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void WhoIsRight_Click(object sender, RoutedEventArgs e)
        {
            var store = new GenericDataStore();

            try
            {
                var data = new MyPrivateClass();
                store.StoreTheData(data);
                object theData = store.GetTheData<MyPrivateClass>();
                if (theData == null || !(theData is MyPrivateClass))
                {
                    throw new Exception();
                }
                MessageBox.Show("Seann was right.");
            }
            catch (Exception)
            {
                MessageBox.Show("WOOOOOOOOOT!!!!! PHIL WINS!!!!!! HAHAHAHA!!!!!! PWNED!!!!!!!");
            }
        }

        private class MyPrivateClass
        {

        }
    }
}

namespace MyNamespace
{
    public class GenericDataStore
    {
        readonly List<object> _store = new List<object>();

        public void StoreTheData<T>(T data)
        {
            _store.Add(data);
        }

        public object GetTheData<T>()
        {
            //How does "t is T" work if T is a private type unknown to this class?
            return _store.FirstOrDefault(t => (t is T));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

代码中突出了其工作原理的问题."是"是否需要强制转换为T以确定它是否实际上是T?它不需要这种类型可访问吗?显然情况并非如此,所以突出显示的行使用什么机制来确定它?

Eri*_*ert 9

以这种方式思考:

class C
{
    private const int BigSecret = 0x0BADFOOD;
    public static void M() { D.X(BigSecret); }
}
class D
{
    public static void X(int y) { Console.WriteLine(y); }
}
Run Code Online (Sandbox Code Playgroud)

当CM被调用时,DX会学习秘密并与世界分享.BigSecret是私有的这一事实无关紧要; 你传递了它的价值.不允许代码查看私有字段的,不允许使用私有字段的名称.X完全可以自由地使用y的值,因为它认为合适; 它没有做任何违法行为,比如试图使用BigSecret 的名称.

类型参数的方式相同.它们是逻辑上传递给泛型函数的参数.当然它们并没有使用相同的机制传递,但从逻辑上讲,它们只是传递的参数设置了类型参数的值,就像常规参数设置形式参数的值一样.如果您不想传递秘密私有类型,则不要将其作为类型参数传递.

在你的情况下,StoreTheData不允许使用PrivateClass 的名称,但如果传递PrivateClass 的,它可以使用它想要的一切.如果您不想使用它,那么您不应该通过它.就像你不想知道BigSecret一样,那么你不应该传递它.秘密共享不再是秘密.

顺便提一下,我们利用泛型类型不对其类型参数进行可访问性检查以使匿名类型工作的事实.有关详细信息,请参阅有关该主题的文章

http://blogs.msdn.com/b/ericlippert/archive/2010/12/20/why-are-anonymous-types-generic.aspx


Mar*_*son 5

我认为你混淆了两个独立的概念 - 可见性和运行时类型信息.

每个结构/类都有类型信息.如何获得该类型信息并不重要.例如,您可以反映一个程序集并挖掘出一些私有类型,并且该GetTheData<T>方法仍将按预期运行.

在这种情况下,MyPrivateClass您传入的类型在调用站点处可见(MyPrivateClass嵌套在主类中,因此可见).因此,您知道呼叫站点的类型并将其传递给GetTheData<T>方法.

此时,类型的信息是已知的,并作为泛型类型参数传递.然后,您的代码使用该泛型类型参数进行类型检查.

做这个:

GetTheData<T>()
{
    Console.WriteLine("Type information: {0}", typeof(T).FullName); 
}
Run Code Online (Sandbox Code Playgroud)

如果使用类型调用此方法MyPrivateClass- 它将按预期打印类型的名称.

*编辑 - 删除了有关Type比较的内容,因为Eric L指出is/as运算符有一条IL指令,我不确定除此之外会发生什么.出于问题的目的,您需要知道的是运行时知道类型并且可以愉快地比较它们.

  • 你错了."是"和"as"运算符有自己的IL指令进行类型检查.他们不依赖于反思.见http://blogs.msdn.com/b/ericlippert/archive/2010/09/16/is-is-as-or-is-as-is.aspx (2认同)