Is "where T: class" in any way not applicable at compile time or runtime?

In the following code, I pass the structure to the constructor waiting for the class. Why is this compiled and executed without errors (and produces the desired result)?

class Program { static void Main() { var entity = new Foo { Id = 3 }; var t = new Test<IEntity>(entity); // why doesn't this fail? Console.WriteLine(t.Entity.Id.ToString()); Console.ReadKey(); } } public class Test<TEntity> where TEntity : class { public TEntity Entity { get; set; } public Test(TEntity entity) { Entity = entity; } public void ClearEntity() { Entity = null; } } public struct Foo : IEntity { public int Id { get; set; } } public interface IEntity { int Id { get; set; } } 

If I change my Main() method to include the ClearEntity() call as shown below, it still does not generate errors. Why?

 static void Main() { var entity = new Foo { Id = 3 }; var t = new Test<IEntity>(entity); Console.WriteLine(t.Entity.Id.ToString()); t.ClearEntity(); // why doesn't this fail? Console.ReadKey(); } 
+6
source share
4 answers

where TEntity : class causes TEntity be a reference type, but an interface such as IEntity is a reference type.

See here: http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.80).aspx

where T: class | The type argument must be a reference type, including any class, interface, delegate, or array type

As for your second question, you might think that t.ClearEntity() will not work, because it assigns null to a variable whose type is the type of the value, but it is not. The compilation time type Entity is the IEntity reference type, and the execution type (after assignment) is the null type. That way, you will never have a variable of type Foo , but null .

+8
source

from C # documentation:

where T: class

The type argument must be a reference type, including any class, interface , delegate, or array type. (See note below.)

Since you are passing a structure through an interface, it is still considered a reference type.

+2
source

Within the .net runtime, each type of non-NULL value has an associated reference type (often called a "boxed field type") that derives from System.ValueType . Saying Object Foo = 5; will not actually store Int32 in Foo ; instead, it will create a new instance of the reference type associated with Int32 and save the reference to that instance. The class constraint for a generic type indicates that the type in question should be a kind of reference type, but by itself excludes the possibility that this type can be used to pass a reference to an instance of the type with a short value. In most contexts, outside of general type constraints, interface types are treated as class types.

It is important to note that not only box-type value types are stored as reference types; they behave like reference types. For example, List<string>.Enumerator is a value type that implements IEnumerator<string> . If one has two variables of type List<string>.Enumerator , copying one to the other will copy the state of the enumeration, so there will be two independent and independent enumerations that point to the same list. Copying one of these variables to a variable of type IEnumerator<string> will create a new instance of the boxed value type associated with List<string.Enumerator and save the link to this new object (which will be the third independent enumerator) in the last variable. However, copying this variable to another type of IEnumerator<string> simply save the reference to the existing object (since IEnumerator<string> is a reference type).

The C # language tries to pretend that value types come from Object , but within the .net Runtime kinetics they really don't. Instead, they are convertible to types that are inferred from System.ValueType (which, in turn, comes from Object ). The latter types satisfy type restrictions, although the former will not. By the way, despite its name, System.ValueType is actually a class type.

+1
source

I also suggested that the constraint class keyword means the same class as the class type declaration keyword, but it is not.

As explained in other answers, the term class is overloaded here, which seems to me a terrible solution for C #. Something like referencetype would be more useful.

0
source

Source: https://habr.com/ru/post/925955/


All Articles