简体   繁体   中英

C#: Why does dynamic help determine type argument for use in generic methods?

I'm working with reflection to create some meta-tests to ensure equality between two instances of the same type. As such, I'm using a lot of vars and generics. One thing I've noticed is that with my generic functions, sometimes the Type argument is object (presumably when it can't determine the type) and other times it's the correct type.

Example:

Generic methods

public static RT[] CreateArrayWithNumItems<RT>(RT baseArgument, int numItems)
{
    var a = new List<RT>();
    for (int i = 0; i < numItems; i++)
    a.Add((RT)DataObjectCreator.CreateUninitializedObject(typeof(RT)));
    return a.Select(x => (RT)x).ToArray();        
}  //actual implementation more complex

private static T UnboxObject<T>(T boxedObject)
=> boxedObject;

public static object CreateUninitializedObject(Type typeObject)
=> typeObject == typeof(string) ? "" : FormatterServices.GetUninitializedObject(typeObject);

Use of methods:

            var a = Model.GetType();
            var unitializedObject = CreateUninitializedObject(a);  //returns typed object
            var objectArray = CreateArrayWithNumItems(unitializedObject, 1); //returns object array
            var uob = UnboxObject(unitializedObject);  //returns typed object
            var uobObjectArray = CreateArrayWithNumItems(uob, 1);  //returns object array
            var typedArray = CreateArrayWithNumItems((dynamic) unitializedObject, 1); //returns typed object array

This seems strange to me (aka I'm missing some knowledge), so I have a few questions about it.

Given the same variable, why does UnboxObject return a typed object and CreateArrayWithNumItems return an array of object?

Given the typed object uob why does CreateArrayWithNumItems return an array of object?

Lastly (and most importantly), why does casting to dynamic prior to calling CreateArrayWithNumItems allow the generic method to determine the type?

Without dynamic , the compiler performs all the type evaluations based on static analysis; assuming that CreateUninitializedObject returns object (presumably via FormatterServices ), the call to CreateArrayWithNumItems infers the generic type parameters based on that static type, ie

var objectArray = CreateArrayWithNumItems(unitializedObject, 1);

becomes

var objectArray = CreateArrayWithNumItems<object>(unitializedObject, 1);

precisely because unitializedObject is object .


With dynamic , the runtime performs the work, but now it has knowledge of the actual object at runtime, so it knows that the type is (whatever Model is). The runtime then constructs something like :

dynamic objectArray = CreateArrayWithNumItems<TheActualType>((TheActualType)unitializedObject, 1);

(how it actually does it is much more complex; it could look for non-generic methods too, for example)


So yes, using dynamic can be a sneaky way to go from reflection ( object / Type ) code to strongly-typed generic code, but: it has a cost: dynamic involves more work at runtime - additional reflection, and additional runtime IL emit. You also need to be aware that typedArray is now also dynamic (unless you cast it to something else), so everything you do with typedArray becomes dynamic . Increasing costs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM