views:

62

answers:

1

I'm using anonymous types to pass collections of typed objects to a TemplateResolver, where the named placeholders in a newly instantiated text template may source values from multiple objects, e.g.

var body = TemplateResolver.ResolveTemplate(template.ExternalRecipientBody, new {Sender = customer, NewJobCard = jobCard});

where the template has placeholders like {Sender$Surname} and {NewJobCard$JobNumber}.

Inside ResolveTemplate I need Sender and NewJobCard to be strongly typed, without knowing what to cast them to.

SOLUTION SO FAR

I have come up with this so far, but dislike having to use a string member name. I have asked another question on the possibility of somehow lmbda'ring the string out of at least the method call, even if not the method body.

    private T GetAnonymousTypeMember<T>(object anonymousType, string memberName) where T: class 
    {
        var anonTypesType = anonymousType.GetType();
        var propInfo = anonTypesType.GetProperty(memberName);
        return propInfo.GetValue(anonymousType, null) as T;
    }
+1  A: 

Anonymous types only have method scope, therefore you won't be able to access the strongly typed properties in the "ResolveTemplate" method.

You've got 2 choices:

  1. Box/unbox
  2. Bite the bullet and declare a struct/class

If you need "resolve" the properties from multiple sources, then consider using a form of OO abstraction (interface/abstract class) to pass the types around.

RPM1984
While I agree that this is a good place for a simple DTO-style class, be careful about saying anonymous types are only local. That's not entirely the case. For example, you can pass an instance to a generic method.
Steven Sudit
@Steven - but what 'type' would the generic method accept? Are you talking about a generic delegate method which accepts type 'object'?
RPM1984
An anonymous type is as real as any other; it just can't be referenced by name. So, for example, if you have a generic utility method that takes an IEnumerable<T> and returns a MyList<T>, it would work just fine. The return value would have to be held in a variable declared as `var`.
Steven Sudit
@Steven - exactly. The 'type' accepted by the utility method is still bound by an interface (hence mentioning this in my original answer). Meaning he would need to project that anonymous type into a concrete type deriving from that interface. He can't project that anonymous type straight into a List<T> for example, what would <T> be - it would still need to be a class/struct. Anyway, point taken.
RPM1984
@RPM1984: No, he really *can* make a `List<T>` without ever knowing the name of `T`. That's the whole point! In fact, that's what happens when you call `IEnumerable<T>.ToList()` where `T` is some anonymous type. The rest of what you said is right: outside the context of the method that created the instance of the anonymous type, you'd need reflection or `dynamic` to get at the properties. There's actually an exception to this that Jon Skeet pointed out, but it's hacky beyond all hacks, so I'd rather not get into it. :-)
Steven Sudit
@Steven - point taken. Forgot about that. Hard to visualize something without seeing code. =)
RPM1984
@RPM: Sorry, I would have included a short sample that I'm sure would have been clearer than all this talk, talk, talk, but there doesn't seem to be a good way to format comments and I really didn't want to open an answer when this is really just commentary. Your original answer was fundamentally correct.
Steven Sudit
Guys, I have added my solution so far.
ProfK