2015-12-13 25 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

绝对标记你的答案,如果它回答你的问题:) –