0

I want have a "pointer" to an object but the object can be one of two classes.

QuickFix.Message newOrderSingle;

            if (ecn.versionFIX.Equals(VersionFIX.FSS_FIX44))
            {
                newOrderSingle = new QuickFix.FIX44.NewOrderSingle(
                    new ClOrdID(masterForm.OrderBook.GetNewClOrdIDBroker(ecn.brokerCode)),
                    new Symbol(symbol),
                    new Side(side),
                    new TransactTime(DateTime.Now),
                    ordType = new OrdType(OrdType.LIMIT));
            }
            else
            {
                newOrderSingle = new QuickFix.FIX42.NewOrderSingle(
                    new ClOrdID(masterForm.OrderBook.GetNewClOrdIDBroker(ecn.brokerCode)),
                    new HandlInst('1'),
                    new Symbol(symbol),
                    new Side(side),
                    new TransactTime(DateTime.Now),
                    ordType = new OrdType(OrdType.LIMIT));
            }

Then later I want to do this, where "set" is a method of QuickFix.FIX44.NewOrderSingle:

newOrderSingle.Set(new Price(limitPrice));

Instead I have to do:

((QuickFix.FIX44.NewOrderSingle) newOrderSingle).Set(new Price(limitPrice));

Which is hard to read.

Can I change "cast" of NewOrderSingle dynamically in some way?

Rawling
  • 49,248
  • 7
  • 89
  • 127
ManInMoon
  • 6,795
  • 15
  • 70
  • 133
  • how do you mean, "dynamically"? what are the other options here that make it "dynamic"? What problem is the current cast causing? – Marc Gravell May 01 '15 at 10:51
  • Perhaps dynamic is not the right word. I want to "change" newOrderSingle to be either QuickFix.FIX42.NewOrderSingle QuickFix.FIX44.NewOrderSingle depending on the value of ecn.versionFIX – ManInMoon May 01 '15 at 10:53
  • 1
    Sounds like your two types should implement a common interface or have a common abstract base class... And no, you can't change the type of a variable (which is a *compile-time* choice) at execution time. – Jon Skeet May 01 '15 at 10:53
  • Is it possible to create an interface for classes were not created(written) by me? – ManInMoon May 01 '15 at 10:56
  • if `NewOrderSingle` derive from `QuickFix.Message` you can create the `Set` method in the `QuickFix.Message` instead and make it abstract so that the derived classes such as `NewOrderSingle` can implement it. Like that you wont need to cast. Other solution is simply using reflection but in this case i think it's much cleaner to use an abstract method. – Franck May 01 '15 at 11:03
  • @JonSkeet I see "dynamic" - is that a possible solution? – ManInMoon May 01 '15 at 11:24
  • @ManInMoon: Well it's *an* option, but not as nice a one as having an interface or an abstract class to represent common operations. We don't know where this code comes from, whether these are partial classes or not etc, which doesn't help. – Jon Skeet May 01 '15 at 11:44

3 Answers3

1

You have some options:

dynamic

You can use dynamic keyword to make "duck typing":

dynamic order= newOrderSingle;
order.Set(new Price(limitPrice));

Unfortunately, you loose intellisense and will get RuntimeBinderException when order has not such a method (is of type FIX42 f.e.).

GenericInvoker

You can use my library:

newOrderSingle.DetermineType()
              .When((QuickFix.FIX42 msg) => msg.Set(/* ... */))
              .Resolve();

Unfortunately, you need to hardcode type.

To sum up If you need to use such approach, your classes are badly designed. Consider creating base / abstract class or some inteface:

interface IMessageSetable
{
    Set(Price p);
}

public class FIX44 : IMessageSetable
{ 
    // impl
}

then:

if (newOrderSingle is IMessageSetable)
      ((IMessageSetable)newOrderSingle).Set(price);
  • Unfortunately, the FIX44 and FIX42 classes are not mine - they are from a dll. So I do not think I can use the interface approach can I? – ManInMoon May 01 '15 at 12:58
  • @ManInMoon so, you can create wrapper class (that inherits from FIX44 and implements interface). –  May 01 '15 at 15:41
0

if you have access to the source code of QuickFix.Message, you can add it. perhaps you can add the set function to a common interface.

the really dirty way is using reflection. the code would look like this:

newOrderSingle.GetType().GetMethod("Set").Invoke(newOrderSingle, new Price(limitPrice)));

(I guess it will not compile directly, the function parameters needs to be adjusted)

you could also try to use the dynamic datatype

user287107
  • 9,286
  • 1
  • 31
  • 47
0

As long as you use the common base class QuickFix.Message you cannot use specific members without casting.

If you have a piece of code where you work with a specific subclass you can do:

if(newOrderSingle is QuickFix.FIX44.NewOrderSingle)
{
    QuickFix.FIX44.NewOrderSingle ord44 = (QuickFix.FIX44.NewOrderSingle)newOrderSingle;
    // from here on you can work with ord44:
    ord44.Set(new Price(limitPrice));

    // more code which uses ord44
}
DrKoch
  • 9,556
  • 2
  • 34
  • 43