How do common methods know about inaccessible types? (Or "How did I lose a dollar")

So, we had a small bet on our team, whether something will work or not. I've lost. Here is the code:

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

The question of why it works is highlighted in the code. Do you need to throw in T to determine if it is really T? And isn't a type needed to be available for this? Obviously, this is not so, so what mechanism does the leased line use to determine?

+4
source share
3 answers

Think of it this way:

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

When CM is called, DX learns the secret and shares it with the world. The fact that BigSecret is private does not matter; you conveyed its meaning. The code is not forbidden to see the value of the private field, it is forbidden using the name of the private field. X is completely free to use the value of y at his discretion; he is not doing anything illegal, for example, trying to use the name BigSecret.

Type arguments are similar. They logically pass arguments to a common function. Of course, they are not transmitted using the same mechanisms under the hood, but logically they simply pass arguments that set the values โ€‹โ€‹of the type parameter, just like regular arguments set the values โ€‹โ€‹of formal parameters. If you do not want to pass a secret private type, do not pass it as a type argument.

In your case, StoreTheData is not allowed to use the name PrivateClass, but if you pass the value PrivateClass, it can use whatever it wants. If you do not want it to be used, you should not have skipped it. Just as if you did not want BigSecret to be known, then you should not transmit it. A secret shared is no longer a secret.

By the way, we use the fact that the generic type does not check the availability of its type parameters in order to make anonymous types. For more information, see my article on this topic:

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

+9
source

I think you are mixing two separate concepts - visibility and runtime information.

Each structure / class has type information. How you get type information is not important. For instance. you could think of an assembly and dig up some private type, and the GetTheData<T> method would function properly.

In this case, the type of MyPrivateClass that you pass is displayed on the call site (since MyPrivateClass nested inside your main class and thus displayed for it). So you know the type on the call site and pass it to the GetTheData<T> method.

At this point, type information is known and passed as a parameter of the general type. Your code then uses this generic parameter type to check the type.

Do it:

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

If you call this method with type MyPrivateClass , it will print the type name as expected.

* edited - materials on the Type comparison were deleted, as Eric L indicated that there is an IL instruction for is / as statements, and I'm not sure what happens beyond this point. For the purpose of the question, all you need to know is that the runtime knows about types and can quite successfully compare them.

+5
source

Your private type is displayed inside the class in which it is defined, and therefore there is no problem defining the scope. You can also do something like:

 public interface ISomeInterface { } public class SomeInterfaceFactory { private class SomeClass : IAnInterface { } public ISomeInterface Create() { return new SomeClass(); } } 

Now the externally created ISomeInterface actually an instance of SomeClass , which you can check with reflection, even if this class is private to SomeInterfaceFactory .

+1
source

All Articles