Suppose you have an interface like this:
public interface IDoSomething<out T>
{
T DoSomething(object value);
}
To be able to call DoSomething
on that interface without knowing the type of T
, you have to create this:
开发者_开发知识库public interface IDoSomething
{
object DoSomething(object value);
}
Modify your original interface to inherit from the new one:
public interface IDoSomething<out T> : IDoSomething
{
new T DoSomething(object value);
}
And then do this:
((IDoSomething)obj).DoSomething();
'''But''' then you have to implement the DoSomething
method on your implementation twice; once explicitly and once implicitly.
One solution that partly works is to do this:
((IDoSomething<object>)obj).DoSomething();
But this only works if the generic type is a reference type; value types like DateTime
and int
won't work, even though they too inherit from object
. Why is this?!
Is there a solution to this conundrum yet (without employing abstract classes!)?
Well value types are not supported.
Implication and the reason behind, as far as I know, mainly involves the difference in storage of arrays.
Let's imagine we have:
Byte[] bb = new Byte[20];
byte b = 255;
bb[0] = b; // here value is copied into the array
b = 128;
Console.WriteLine(bb[0]); // will print 255
So changing the b does not change the value we have assigned and this is expected. But what if we do something like this:
object[] bb = new Byte[20]; // throws exception
System treats object arrays differently and stores the pointer and not the value. We actually have only one type of object array (from the structure point of view not type) and that is pointer array while arrays for value types store the value.
This article explains why variance doesn't work for value types (about 1/4 the way down). Basically, int
-> object
changes the representation of the data (it requires boxing), where as string
-> object
simply changes the pointer type.
Within the common language runtime environment, every value-type definition actually defines two kinds of objects: a heap object type which derives from System.Object
and behaves like it, and a storage location type which behaves as a collection of bytes which don't really inherit from anything, and whose meaning depends entirely upon the code that accesses it. If one passes a value type to a routine that expects a heap object reference, the system will create a new heap object (of the appropriate heap object type), copy the value type's data to that object, and pass a reference to that. On the other hand, if one calls a generic method with a value type as one of its generic type parameters, the runtime will generate a special version of that method just for that particular value type; the code in question will know how to interpret the bytes that have been allocated to hold any variables of that type.
Code which expects an IEnumerable<Object>
will be perfectly happy with any IEnumerable<T>
that returns things that really descend from Object
. An IEnumerable<Int32>
, however, does not return instances of the heap type associated with Int32
(which does derive from Object
), but instead returns collections of bytes which would be meaningless to any code which wasn't specifically generated to deal with values of type Int32
.
精彩评论