[英]C# Dynamics: Convert.ChangeType versus Cast
有人可以解釋為什么在使用Convert.ChangeType時,將動態對象作為類返回該類會返回動態對象,特別是在運行時嗎? 例如:
dynamic dObject = new SomeClass();
var dTest1 = dObject as SomeClass; // returns SomeClass
var dTest2 = Convert.ChangeType(dObject, typeof(SomeClass)); // returns dynamic
更廣泛的問題:我有一系列輔助類來實現通用接口。 我需要將這些類的列表傳遞給其他對象; 但是不同的幫助器類對泛型參數使用不同的類型,所以我不能直接傳遞輔助類的列表:
interface IHelper<T>
{
IEnumerable<T> Foo();
}
var HelperList = new List<IHelper<T>> // Can't do this because T varies from helper to helper!
所以我認為我可以通過創建一個包含輔助類和泛型類型的容器類來偽造運行時,但是利用了動態:
class ContainerClass
{
IHelper<dynamic> HelperClass;
Type dType; // Specifies the type for the dynamic object
}
現在我可以創建並傳遞一個ContainerClass列表。 所有處理工作都很好,直到我需要將Foo()的結果分配回目標IEnumerables,此時我得到運行時錯誤,說明類型對象無法轉換為這樣的具體類,即使未裝箱的對象類型匹配那些要求。 如果我嘗試上面的dTest2中的類似語法,運行時仍然無法找出“轉換”。
我意識到這可能是濫用動態和糟糕的編程習慣來啟動的。 如果我能找到一個解決方案,我當然會使用不同的解決方案,但是現在我要么需要做這個工作,要么選擇不那么雄心勃勃的東西。
在執行時,真的沒有dynamic
。
但是,對Convert.ChangeType
的調用是提供dynamic
值作為參數。 使用dynamic
參數的任何方法調用都被視為具有dynamic
的返回值,因為編譯器在執行時間之前不知道實際簽名是什么。
但是,如果使用強制轉換, is
或as
表達式,或構造函數調用,則結果只有一種類型 - 這就是表達式的類型。
至於你更廣泛的問題 - 我不清楚使用dynamic
會特別有助於你。 您可能希望為IHelper<T>
聲明一個基本接口 - 一個非泛型接口,它只用於實際的IHelper<T>
實例。 然后你可以得到一個List<IHelper>
,其中每個元素實際上是一些T
的IHelper<T>
,但是T
在實例之間變化。 這里並不真正需要 IHelper
接口,但如果你的IHelper<T>
接口確實包含其他不使用T
成員,那么可以將它們移動到IHelper
。 然而,僅僅為了清晰起見可能是有用的。
現在,當你需要使用特定的IHelper
, 那么動態類型可以簡單地是有用的。 您可以聲明一個泛型方法,並讓動態類型在執行時找出類型參數。 例如:
private readonly IList<IHelper> helpers;
...
public void UseHelpers()
{
foreach (dynamic helper in helpers)
{
UseHelper(helper); // Figures out type arguments itself
}
}
private void UseHelper<T>(IHelper<T> helper)
{
// Now you're in a generic method, so can use T appropriately
}
根據Jon Skeet的回答,我認為你可以做一些非常有趣的事情並避免使用動態關鍵字,因為它會影響性能。
使用IHelper<T> : IHelper
。 現在,您可以將幫助程序存儲到List<IHelper>
。 現在你可以通過將類型maping到泛型方法來調用Foo方法。
public IEnumerable<T> UseHelper<T> (IHelper<T> helper)
{
}
delegate IEnumerable<object> UseHelperDelegate(IHelper helper)
Dictionary<Type, UseHelperDelegate> helpersMap;
helpersMap.Add(typeof(int), UseHelper<int>); // Add others if you want
public IEnmerable<object> UseHelperWithMap(IHelper helper)
{
Type helperType = helper.GetType();
IEnumerable<object> retValue;
if (helpersMap.Contains(helperType))
{
retValue = helpersMap[helperType](helper);
}
else // if the type is not maped use DLR
{
dynamic dynamicHelper = helper;
retValue = UseHelper(dynamicHelper)
// I wonder if this can actually be added to the map here
// to improve performance when the same type is called again.
}
}
注意:您可以投IEnumerable<SomeClass>
到IEnumerable<object>
和UseHelper<SomeClass>
到UsehelperDelegate
因為協變和逆變 。
編輯:事實證明,你可以從通用創建一個新的具體功能,並將其添加到地圖。 這樣就可以避免使用dynamic
。
var useHelperGeneric = this.GetType().GetMethods().FirstOrDefault(
m=> m.IsGenericMethod && m.Name == "UseHelper");
var useHelper = useHelperGeneric.MakeGenericMethod(new Type[] { helper.GetType() });
var newFunction = (UserHelperDelegate)useHelper.MakeDelegate(typeof(UseHelperDelegate));
helpersMap.Add(helper.GetType(), newFunction);
newFunction(helper);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.