2016-03-14 42 views
0

我有以下問題與T和泛型方法的選項將其限制爲例如。一個引用類型(其中T:class)。所以,我得到了下面的代碼:強制T作爲代碼中的參考類型[CS0452錯誤]

public void mySave<T>(string filename, T obj) 
{ 
    Session s = connect(filename); 
    s.Save(obj); 
} 

public Document Save<TEntity>(TEntity entity) where TEntity : class; 

沒有辦法申報mySave where T : class因爲我從一個接口得到它。無論如何,我需要解決CS0452 (The type 'type name' must be a reference type in order to use it as parameter 'parameter name' in the generic type or method 'identifier of generic')

任何想法呢?

+2

要麼你必須犧牲一些類型的安全性,並使用反射或在界面中添加約束。 –

回答

1

Sriram提出了兩種方法......更正確的方法(由MatíasFidemraizer探索)是改變界面。另一種方式是通過反思。我完全支持MatíasFidemraizer探索的方式,並認爲這是「正確」的方式。但有時你不能做正確的事情,你必須做一些有效的事情。

這是通過反思的另一種方式。請注意,此代碼進一步超出必要,緩存委託,以便使用相同的T類型的進一步調用將不需要重用反射,並且會更快。

public static class SessionHelper 
{ 
    public static void Save2<T>(this Session session, T obj) 
    { 
     SessionHelperImpl<T>.Save(session, obj); 
    } 

    private static class SessionHelperImpl<T> 
    { 
     public static readonly Action<Session, T> Save; 

     static SessionHelperImpl() 
     { 
      MethodInfo saveT = (from x in typeof(Session).GetMethods() 
           where x.Name == "Save" && x.IsGenericMethod 
           let genericArguments = x.GetGenericArguments() 
           where genericArguments.Length == 1 
           let parameters = x.GetParameters() 
           where parameters.Length == 1 && parameters[0].ParameterType == genericArguments[0] 
           select x).Single(); 

      MethodInfo save = saveT.MakeGenericMethod(typeof(T)); 

      Save = (Action<Session, T>)save.CreateDelegate(typeof(Action<Session, T>)); 
     } 
    } 
} 

這樣使用它:

s.Save2(obj); 

請注意,如果你嘗試通過非引用類型爲obj你會得到一個TypeInitializationException。你不能真的繞過Savewhere T : class。您只能在編譯期間繞過它,並將其延遲到運行時。

2

如果某些泛型參數有一些約束,那麼用作參數的任何其他泛型參數都必須至少提供相同的類型保證。由於泛型是一個編譯時的特性,試想Save<TEntity>要求TEntity是一個引用類型,並且可以給出一個參數,該參數可能是或可能不是值類型。這將打敗仿製藥的目的。

最好的辦法是將整個通用約束(即T : class)添加到接口中。

+0

所以它不可能以任何方式檢查這個硬編碼?像'if(typeof(T).IsClass){檢查這裏並且調用s.Save } {else錯誤}'? – pytomaniaq

+0

@pytomaniaq Nope –

+0

@pytomaniaq嗯,這可能與反思(或'動態')。但正如馬蒂亞斯指出的那樣,這種做法有失於目的 - 你會失去編譯時的安全性。你爲什麼要這麼做,而不是確保界面本身受到限制? – Luaan