connamara / quickfixn

QuickFIX/n implements the FIX protocol on .NET.
http://quickfixn.org
Other
469 stars 557 forks source link

Cannot cast generic 'Group' to 'NoMDEntriesGroup' #56

Closed loganm closed 12 years ago

loganm commented 12 years ago

Hi all,

I'm trying to get a Group out of a message, but the generic group won't cast into the specific group variable.

The following code is based on the example shown on the website at http://quickfixn.org/tutorial/repeating-groups

public void OnMessage(QuickFix.FIX42.MarketDataIncrementalRefresh message, SessionID sessionID)
{
    MDReqID mdReqID = message.MDReqID;
    var noMDEntriesGroup = new QuickFix.FIX42.MarketDataIncrementalRefresh.NoMDEntriesGroup();
    for (int grpIndex = 1; grpIndex <= message.GetInt(Tags.NoMDEntries); grpIndex += 1)
    {
        noMDEntriesGroup = message.GetGroup(grpIndex, Tags.NoMDEntries);
        // code omitted here
    }
}

It generates the following error in Visual Studio

Error 1 Cannot implicitly convert type 'QuickFix.Group' to 'QuickFix.FIX42.MarketDataIncrementalRefresh.NoMDEntriesGroup'. An explicit conversion exists (are you missing a cast?)

According to the error message, I tried an explicit conversion to no avail (code follows). Doing this got rid of the Visual Studio error message, but resulted in an InvalidCastException at runtime.

noMDEntriesGroup = (QuickFix.FIX42.MarketDataIncrementalRefresh.NoMDEntriesGroup)message.GetGroup(grpIndex, Tags.NoMDEntries);

Thanks, Logan

gbirchmeier commented 12 years ago

Mail list thread: http://lists.quickfixn.com/pipermail/quickfixn-quickfixn.com/2012q2/000124.html

gbirchmeier commented 12 years ago

Has anyone looked at how Java does it?

judwhite commented 12 years ago

A bit heavy handed, but would this work?

public void OnMessage(QuickFix.FIX42.MarketDataIncrementalRefresh message, SessionID sessionID)
{
    MDReqID mdReqID = message.MDReqID;

    int count = message.GetInt(Tags.NoMDEntries);
    var list = new List<QuickFix.Group>();
    for (int grpIndex = 1; grpIndex <= count; grpIndex++)
    {
        list.Add(message.GetGroup(grpIndex, Tags.NoMDEntries));        
    }

    foreach (var noMDEntriesGroup in list.OfType<QuickFix.FIX42.MarketDataIncrementalRefresh.NoMDEntriesGroup>())
    {
      // code omitted here
    }
}

If you're expecting them to all be NoMDEntriesGroup you might replace OfType with Cast.

judwhite commented 12 years ago

Sorry I missed the part where you already tried the explicit cast. The above code probably won't be of any use.

loganm commented 12 years ago

Unfortunately, bigger hammers aren't the solution here. I've tried :).

So as far as a solution in code, what does everyone else think is the best method?

I'm a bit pressed for time but am willing to do some work on this. It'll make my life easier in the long run so my boss shouldn't mind.

gbirchmeier commented 12 years ago

We'd really like to maintain some semblance of similarity between QF/n and QF for C++/Java.

I'd really like to see how QF/J handles this. They might have a design we can steal. I'll have a look later if I can find the time.

blackhill commented 12 years ago

I had the same problem with a MarketDataSnapshotFullRefresh.

A workaround was :

       QuickFix.Group mdGroup;

       for(int i = 1; i < message.GetInt(Tags.NoMDEntries);i++)
       {
           mdGroup = message.GetGroup(i, Tags.NoMDEntries);

           Console.WriteLine(mdGroup.GetString(Tags.MDEntryPx));
           Console.WriteLine(mdGroup.GetString(Tags.MDEntrySize));
       }

Hope this help !

S

loganm commented 12 years ago

That's how I ended up having to do it. Thanks Steven.

This is still a bug, so how should we go about fixing it? I don't mind doing some of the work, but I wouldn't want to attempt anything without guidance. I'm new to contributing to open source projects.

gbirchmeier commented 12 years ago

Notes on methods of other QF versions:

QF: msg.getGroup(1,group_object) (this is a member of Message, not FieldMap) QF/j: msg.getGroup(1,group_object) and group_object=msg.getGroup(1,tag_int) (each are from FieldMap) QF/n: group_object = msg.GetGroup(1, tag_int)

Java: http://quickfixj.org/quickfixj/usermanual/1.5.1/usage/repeating_groups.html C++: http://www.quickfixengine.org/quickfix/doc/html/repeating_groups.html

gbirchmeier commented 12 years ago

Unit tests: https://github.com/gbirchmeier/quickfixn/tree/56_group

gbirchmeier commented 12 years ago

I see the root cause now. When Message::FromString() creates a Message object from a string, it constructs Group objects instead the type-specific subclasses of Group. Therefore, the objects retrieved by GetGroup() are also Group objects. You can't cast a base class to a subclass if it was never a subclass-type object in the first place.

So I need to see if we have some kind of Group factory to create the typed Group objects. If we don't, then I guess I need to generate one.

NickT1977 commented 12 years ago

Each of the following classes implements IMessageFactory that has a method called 'Create' that returns a Typed Group object based on the arguments passed in, it has the following signiture: public Group Create(string beginString, string msgType, int correspondingFieldID)

The classes are: QuickFix.FIX40.MessageFactory(); QuickFix.FIX41.MessageFactory(); QuickFix.FIX42.MessageFactory(); QuickFix.FIX43.MessageFactory(); QuickFix.FIX44.MessageFactory();

gbirchmeier commented 12 years ago

Thanks, Nick. I figured it was in there somewhere, but couldn't remember where. With this, I will probably be able to knock this out this week.

gbirchmeier commented 12 years ago

I think I solved it on my branch. Will integrate tomorrow. https://github.com/gbirchmeier/quickfixn/tree/56_group

gbirchmeier commented 12 years ago

Damn, still failing AT 14i in the FIX50x sets.

Note to self: cd AcceptanceTest runat.bat release 5006 definitions\server\fix50\14i_RepeatingGroupCountNotEqual.def cfg\at_50.cfg runat.bat release 5007 definitions\server\fix50sp1\14i_RepeatingGroupCountNotEqual.def cfg\at_50_sp1.cfg runat.bat release 5008 definitions\server\fix50sp2\14i_RepeatingGroupCountNotEqual.def cfg\at_50_sp2.cfg