2015-12-13 74 views
-1

我有一種情況,我有一個不是通用類的類,但它需要存儲集合中通用對象的實例。在下面的例子中,我不能使Foo是通用的,但我需要將請求對象存儲在pendingRequests字典中。下面的代碼將在pendingRequests聲明中給出一個錯誤:「使用泛型類型的Request需要'1'類型參數」,但如果我將<Response>添加到Request中,那麼當我嘗試添加到addRequest中的字典時,我收到了一個投射錯誤。在集合中使用通用類型,而不使用C#中的通用類

我需要使字典聲明通用,但沒有使通用Foo。可以這樣做,還是應該以另一種方式做這件事?爲此添加一個皺紋,我堅持使用.NET 2.0,因爲它需要與Unity 3d協同工作。

class Foo 
{ 
    private Dictionary<int, Request> pendingRequests; 

    void addRequest<T>(int sequence, Request<T> request) where T : Response 
    { 
     pendingRequests[sequence] = request; 
    } 
} 

class Request<T> where T : Response 
{ 
} 

class Response 
{ 
} 
+0

你可以創建一個非泛型'Request'類,它將基礎作爲參數嗎? '請求:請求'? –

+0

你還沒有解釋爲什麼你不能使用泛型... –

+0

不應該是'Dictionary >'和'addRequest(int seq,請求請求)'? –

回答

0

我在回答不同的問題時發現了答案。我可以爲不通用的請求創建基類或接口。通用請求然後從基本的非通用請求中繼承。非泛型請求用於addRequest和Foo中的集合。從我的Java角度來看,這是手動完成我習慣的類型擦除。

class Foo 
{ 
    private Dictionary<int, IRequest> pendingRequests; 

    void addRequest(int sequence, IRequest request) 
    { 
     pendingRequests[sequence] = request; 
    } 
} 

class Request<T> : IRequest where T : Response 
{ 
} 

class Response 
{ 
} 

interface IRequest 
{ 
} 
+0

這是接近,但不提供100%類型的安全性(得到,你沒有提供一種方法,看看我的答案爲100%得到)。確保你檢查你的請求(如果使用接口或抽象基類)。 –

+0

@ErikPhilips它提供的類型安全性非常之多,以至於在IRequest中定義的任何接口都必須完整,這正是我一直在尋找的內容:)基本上,我希望能夠使用Request中定義的成員不依賴於在泛型上,但是因爲我已經把它作爲泛型的(爲了其他內部目的),我被困在Foo中作爲泛型來處理它。我的解決方案是將這些成員的定義移動到IRequest,然後使用它來代替通用請求。應該100%安全 - 無需任何鑄造。那有意義嗎? –

+0

當然,如果你不投射,那麼爲什麼有''......否則你會在某處投射.. –

0

富不能因爲除了保持通用要求的集合通用的,它是獨立完整的請求。有一個Foo實例(將其稱爲會話),但有幾十種不同類型的請求。它並不關心一個請求是一個LoginRequest還是一個BuyMeRequest。但是,Request是通用的,因爲我使用提供的Response類型來構造當前類型的Response對象,並將它從通過線路傳入的數據反序列化。

那麼你的收藏不應該是通用要麼。您可能需要考慮放棄泛型定義並簡單地使用繼承。這應該讓你在路上,雖然不是100%,但你的問題在用法上是模糊的。當然,這使用LINQ(我認爲是3.5+或更高版本),它應該很容易遷移到2.0。

public class Foo 
{ 
    // initialize: best practice 
    private List<CacheRequest> _pendingRequests = 
    new List<CacheRequest>(); 

    // upper case: best practice 
    public void AddRequest(int sequence, Request request) 
    { 
    if (request.Response == null) 
    { 
     throw new ArgumentException("Request Response cannot be null."); 
    } 

    _pendingRequests.Add(new CacheRequest() 
    { 
     Sequence = sequence, 
     Request = request, 
     ResponseType = request.Response.GetType() 
    }); 
    } 

    public bool TryGetRequest<T>(int seq, out Request request, out T response) 
    where T : Request 
    { 
    response = null; 
    request = null; 

    var pendingRequest = _pendingRequests 
     .Where(cr => cr.ResponseType == typeof(T)) 
     .FirstOrDefault(r => r.Sequence == seq); 

    var result = pendingRequest != null; 

    if (result) 
    { 
     request = pendingRequest.Request; 
     response = request.Response as T; 
    } 

    return result; 
    } 

    private class CacheRequest 
    { 
    public int Sequence { get; set; } 
    public Request Request { get; set; } 
    public Type ResponseType { get; set; } 
    } 
} 

public class Request 
{ 
public Response Response { get; set; } 
} 

public abstract class Response { } 

public class HttpResponse : Response { } 

public class UdpResponse : Response { } 

實施例:

var foo = new Foo(); 

    foo.AddRequest(1, new Request() { Response = new HttpResponse() }); 

    Request request; 
    HttpResponse httpResponse; 
    UdpResponse udpResponse; 


    if (foo.TryGetRequest<HttpResponse>(1, out request, out httpResponse)) 
    { 
     Console.WriteLine("1 is an HttpResponse"); 
    } 

    if (!foo.TryGetRequest<UdpResponse>(1, out request, out udpResponse)) 
    { 
     Console.WriteLine("1 is not a UdpResponse"); 
    }  

輸出:

1是一個HttpResponse

1不是UdpResponse

DotNetFiddle Example

+0

謝謝!我想我明白你要去那裏。我相信幾分鐘前發現的基類/接口解決方案可以直接獲得我正在尋找的答案。請回顧一下,除非答案有問題,否則即使我自己寫了一個,我也打算接受這個答案。 –

+0

絕對標記你的答案,如果它回答你的問題:) –