泛型方法如何知道不可访问类型?(或者《我是如何丢了一美元的》)

本文关键字:丢了 何丢了 美元 我是如何丢了一美元的 何知道 访问类型 泛型方法 或者 | 更新日期: 2023-09-27 17:50:16

所以,我们对我们的团队打了个小赌,看看是否可行。我输了。下面是代码:

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));
        }
    }
}

为什么它工作的问题在代码中突出显示。"is"不需要强制转换为T来确定它是否实际上是T吗?它不需要类型是可访问的吗?显然情况并非如此,那么突出显示的行使用什么机制来确定它呢?

泛型方法如何知道不可访问类型?(或者《我是如何丢了一美元的》)

这样想:

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); }
}

当C.M被召唤时,D.X得知了这个秘密并与世界分享。BigSecret是私有的这一事实无关紧要;您传递了它的。不允许代码看到私有字段的,不允许使用私有字段的名称。X完全可以随心所欲地使用y的值;它不会做任何非法的事情,比如试图使用BigSecret的名称

类型参数也是如此。它们是逻辑上传递给泛型函数的参数。当然,它们不是使用相同的机制传递的,但逻辑上它们只是传递设置类型参数值的参数,就像设置形式参数值的常规参数一样。如果你不想传递秘密私有类型,那么不要将其作为类型参数传递。

在您的情况下,StoreTheData不允许使用PrivateClass的名称,但如果传递给PrivateClass的,它可以使用它想要的所有内容。如果你不想让它被使用,那么你就不应该传递它。就像如果你不想让大秘密被人知道,那么你就不应该把它传出去。共享的秘密不再是秘密。

顺便说一下,我们利用了泛型类型不对其类型参数进行可访问性检查的事实来使匿名类型工作。有关详细信息,请参阅我的文章: http://blogs.msdn.com/b/ericlippert/archive/2010/12/20/why-are-anonymous-types-generic.aspx

我想你混淆了两个不同的概念——可见性和运行时类型信息。

每个结构/类都有类型信息。如何获得类型信息并不重要。例如,您可以对程序集进行反射并挖掘出一些私有类型,而GetTheData<T>方法仍然会按预期运行。

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

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

这样做:

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

如果您使用类型MyPrivateClass调用该方法——它将按预期打印该类型的名称。

*编辑-删除的东西关于Type比较埃里克L指出,有一个IL指令的is/as操作符,我不确定发生了什么超出了这一点。对于这个问题,您所需要知道的就是运行时知道类型,并且能够愉快地比较它们。

您的私有类型在定义它的类中是可见的,因此没有作用域问题。你也可以这样做:

public interface ISomeInterface { }
public class SomeInterfaceFactory
{
   private class SomeClass : IAnInterface { }
   public ISomeInterface Create() { return new SomeClass(); }
}
现在外部创建的ISomeInterface实际上是SomeClass的一个实例,您可以通过反射来验证,即使该类是SomeInterfaceFactory私有的。