Dynamically selecting the type of a component given the type of its generic type parameter?

You can solve this with a visitor : interface IPaymentVisitor { void Visit(CreditCard payment); void Visit(StoredCredit payment); } abstract class Payment { public abstract void Accept(IPaymentVisitor visitor); } class CreditCard : Payment { public override void Accept(IPaymentVisitor visitor) { visitor. Visit(this); } } class StoredCredit : Payment { public override void Accept(IPaymentVisitor visitor) { visitor. Visit(this); } } class PaymentTaker : IPaymentVisitor, IPaymentTaker { public void Visit(CreditCard payment) { // ... } public void Visit(StoredCredit payment) { // ... } public PaymentProcessingResult Process(Payment payment) { payment.

Accept(this); // ... } } If you still want to separate the different payment takers, or if your hierarchy jitters, you can use an acyclic visitor (pdf) : interface IPaymentVisitor { } interface IPaymentVisitor : IPaymentVisitor where TPayment : Payment { void Visit(TPayment payment); } abstract class Payment { public abstract void Accept(IPaymentVisitor visitor); } class CreditCard : Payment { public override void Accept(IPaymentVisitor visitor) { if (visitor is IPaymentVisitor) { ((IPaymentVisitor)visitor). Visit(this); } } } class StoredCredit : Payment { public override void Accept(IPaymentVisitor visitor) { if (visitor is IPaymentVisitor) { ((IPaymentVisitor)visitor). Visit(this); } } } class CreditCardPaymentTaker : IPaymentVisitor, IPaymentTaker { public void Visit(CreditCard payment) { // ... } public PaymentProcessingResult Process(Payment payment) { payment.

Accept(this); // ... } } class StoredCreditPaymentTaker : IPaymentVisitor, IPaymentTaker { public void Visit(StoredCredit payment) { // ... } public PaymentProcessingResult Process(Payment payment) { payment. Accept(this); // ... } }.

You can solve this with a visitor: interface IPaymentVisitor { void Visit(CreditCard payment); void Visit(StoredCredit payment); } abstract class Payment { public abstract void Accept(IPaymentVisitor visitor); } class CreditCard : Payment { public override void Accept(IPaymentVisitor visitor) { visitor. Visit(this); } } class StoredCredit : Payment { public override void Accept(IPaymentVisitor visitor) { visitor. Visit(this); } } class PaymentTaker : IPaymentVisitor, IPaymentTaker { public void Visit(CreditCard payment) { // ... } public void Visit(StoredCredit payment) { // ... } public PaymentProcessingResult Process(Payment payment) { payment.

Accept(this); // ... } } If you still want to separate the different payment takers, or if your hierarchy jitters, you can use an acyclic visitor (pdf): interface IPaymentVisitor { } interface IPaymentVisitor : IPaymentVisitor where TPayment : Payment { void Visit(TPayment payment); } abstract class Payment { public abstract void Accept(IPaymentVisitor visitor); } class CreditCard : Payment { public override void Accept(IPaymentVisitor visitor) { if (visitor is IPaymentVisitor) { ((IPaymentVisitor)visitor). Visit(this); } } } class StoredCredit : Payment { public override void Accept(IPaymentVisitor visitor) { if (visitor is IPaymentVisitor) { ((IPaymentVisitor)visitor). Visit(this); } } } class CreditCardPaymentTaker : IPaymentVisitor, IPaymentTaker { public void Visit(CreditCard payment) { // ... } public PaymentProcessingResult Process(Payment payment) { payment.

Accept(this); // ... } } class StoredCreditPaymentTaker : IPaymentVisitor, IPaymentTaker { public void Visit(StoredCredit payment) { // ... } public PaymentProcessingResult Process(Payment payment) { payment. Accept(this); // ... } }.

That's perfect! Thanks Jordao! – Gaz Aug 8 '10 at 11:58.

Interface IPayment { IPaymentTaker Taker {get;} } class CreditCardPayment : IPayment { IPaymentTaker Taker{ get {return new CreditCardPaymentTaker();}} } payment.Taker. Process(payment).

That's a pretty good idea and would work fine in most situations, but I would usually expect the PaymentTakers to be loaded from an IoC container. The more general problem is that this binds the Taker to the payment, which does not allow different Takers for different contexts. – Gaz Aug 6 '10 at 13:47.

Even though James' method is ideal, using an IoC container could be difficult. Here's my Reflection or dynamics based approach. Doing the following will allow you to still use an IoC to setup the mapping between the PaymentTaker and Payment.

Public class Payment { } public class CreditCardPayment : Payment { } public class StoreCreditPayment : Payment { } public interface IPaymentTaker { } public interface IPaymentTaker : IPaymentTaker { void Process(T payment); } public static class PaymentTaker { public static void Process(Payment payment) { var paymentType = payment.GetType(); // You would have these already setup and loaded via your IOC container... var paymentTakers = new Dictionary(); paymentTakers. Add(typeof(CreditCardPayment), new CreditCardPaymentTaker()); paymentTakers. Add(typeof(StoreCreditPayment), new StoreCreditPaymentTaker()); // Get the payment taker for the specific payment type.

Var paymentTaker = paymentTakerspaymentType; // Execute the 'Process' method. PaymentTaker.GetType(). GetMethod("Process").

Invoke(paymentTaker, new object{ payment }); // If . NET 4.0 - dynamics can be used. // dynamic paymentTaker = paymentTakerspaymentType; // paymentTaker.

Process((dynamic)payment); } } public class CreditCardPaymentTaker : IPaymentTaker { public void Process(CreditCardPayment payment) { Console. WriteLine("Process Credit Card Payment..."); } } public class StoreCreditPaymentTaker : IPaymentTaker { public void Process(StoreCreditPayment payment) { Console. WriteLine("Process Credit Card Payment..."); } } And then you can use it like this: var cc = new CreditCardPayment(); PaymentTaker.

Process(cc).

1 Yep that one had occurred to me as well. Probably neater to use dynamic; i.e. Dynamic paymentTaker = paymentTakerspaymentType; paymentTaker.

Process(paymentType). – Gaz Aug 6 '10 at 13:58 Hm, yeah never even though about that if you're using . NET 4.0.

Good point! – TheCloudlessSky Aug 6 '10 at 13:59 So I tried testing dynamic paymentTaker = paymentTakerspaymentType; paymentTaker. Process(payment) and it was throwing an exception so instead you'd need to write paymentTaker.

Process((dynamic)payment); – TheCloudlessSky Aug 6 '10 at 14:03 I don't think the problem calls for reflection. – Steven Sudit Aug 6 '10 at 14:05 @Steven - Never said it did, but I just thought I'd write it for fun... – TheCloudlessSky Aug 6 '10 at 14:07.

If you can ensure the names of the Payment and PaymentTaker match you can use something like this: Process(Payment payment) { String typeName = "YourPathToPaymentTakers. " + payment.GetType(). Name + "Taker"; Type type = typeof(IPaymentTaker).Assembly.

GetType(typeName); IPaymentTaker taker = (IPaymentTaker)Activator. CreateInstance(type);; } I have used this approach in the past, but if you do not have 100% control of the names of the classes this could be a problem.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions