can't shorten the interface
I have this property, which is working fine:
public IEnumerable<IGrouping<MessageType, Message>> MessageGroups
{
get
{
return
(from msg in _messages
orderby msg.Type descending
group msg by msg.Type);
}
}
However, it's causing me to have to repeat the ugly-looking IEnumerable<IGrouping<MessageType, Message>>
in several places in my code. I tried to make this easier on the eyes by defining a trivial wrapper interface like this:
public interface IMessageGroups :
IEnumerable<IGrouping<MessageT开发者_Go百科ype, Message>> { }
and changing the property above to:
public IMessageGroups MessageGroups
{
get
{
return
(IMessageGroups)
(from msg in _messages
orderby msg.Type descending
group msg by msg.Type);
}
}
This builds fine, but at runtime I get:
Unable to cast object of type 'System.Linq.GroupedEnumerable`3[Message,MessageType,Message]' to type 'IMessageGroups'.
(project-specific namespaces removed from the error message)
What can I do to fix this?
You could try using a type alias:
using Foo = IEnumerable<IGrouping<MessageType, Message>>;
And then:
public Foo MessageGroups
{
get
{
return
(from msg in _messages
orderby msg.Type descending
group msg by msg.Type);
}
}
Another possibility is to expand further your LINQ query and select some custom type you create after the grouping:
public IEnumerable<Foo> MessageGroups
{
get
{
return
(from msg in _messages
orderby msg.Type descending
group msg by msg.Type
select new Foo { Messages = g, MessageType = g.Key }
);
}
}
and Foo:
public class Foo
{
public MessageType MessageType { get; set; }
public IEnumerable<Message> Messages { get; set; }
}
If you don't care about lazy evaluation you could put a .ToArray()
at the end of your LINQ query and the return type becomes simply Foo[]
.
It builds fine because the compiler can never know for sure whether the returned type isn't actually a subclass that implements the interface. (Contrast this with a cast to a class instead and you get a compiler error since that is statically known.)
But the fact remains that you are trying to cast the result of the LINQ expression into an interface that it does not implement (the "wrapper" interface). That simply isn't going to work. And nothing you can really do to fix it short of declaring a class that implements it yourself, and actually doing the "wrapping" in your implementation (passing in the existing LINQ expression perhaps to the constructor).
The cast to IMessageGroups
fails because the result of the query is an instance of IEnumerable<IGrouping<MessageType, Message>>
, not an instance of IMessageGroups
. But you could write a MessageGroups
class and use it to wrap the result of the query :
public class MessageGroups : IMessageGroups
{
private readonly IEnumerable<IGrouping<MessageType, Message>> _groups;
public MessageGroups(IEnumerable<IGrouping<MessageType, Message>> groups)
{
_groups = groups;
}
public IEnumerable<IGrouping<MessageType, Message>> GetEnumerator()
{
return _groups.GetEnumerator();
}
public static MessageGroups Create(IEnumerable<IGrouping<MessageType, Message>> groups)
{
return new MessageGroups(groups);
}
}
And use it like that:
public IMessageGroups MessageGroups
{
get
{
return
MessageGroups.Create(
from msg in _messages
orderby msg.Type descending
group msg by msg.Type);
}
}
At the top of your cs file:
using ASimpleName = Dictionary<string, Dictionary<string, List<string>>>;
Source
or in your case:
using ShortName = IEnumerable<IGrouping<MessageType, Message>>;
精彩评论