If you find the double dispatch too intrusive, you can call the method by reflection and resolve the proper overload dynamically protected bool ValidAdvert(Base item) { if (item.GetType() == typeof(Base)) throw new ThisIsAnAbstractClassException(); Type type = typeof(CurrentClass); MethodInfo method = type. GetMethod("ValidAdvert", BindingFlags. Instance | BindingFlags.
NonPublic, null, new Type { item.GetType() }, null); return (bool)method. Invoke(this, new object { item }); } protected bool ValidAdvert(Derived1 item) { return ADerived1SpecificPredicate; } protected bool ValidAdvert(Derived2 item) { return ADerived2SpecificPredicate; } This pattern is called MultipleDispatch while calling a method by reflection is slower than calling the method directly (it won't be an overhead if the method is called less than few hundred times per second), it has the benefit of not requiring to modify your class hierarchy like in the Double Dispatch pattern This will be even easier when c# 4.0 comes out with the dynamic keyword: protected bool ValidAdvert(Base item) { if (item.GetType() == typeof(Base)) throw new ThisIsAnAbstractClassException(); dynamic dynamicThis = this; return (bool)dynamicThis. ValidAdvert(item); }.
If you find the double dispatch too intrusive, you can call the method by reflection and resolve the proper overload dynamically. Protected bool ValidAdvert(Base item) { if (item.GetType() == typeof(Base)) throw new ThisIsAnAbstractClassException(); Type type = typeof(CurrentClass); MethodInfo method = type. GetMethod("ValidAdvert", BindingFlags.
Instance | BindingFlags. NonPublic, null, new Type { item.GetType() }, null); return (bool)method. Invoke(this, new object { item }); } protected bool ValidAdvert(Derived1 item) { return ADerived1SpecificPredicate; } protected bool ValidAdvert(Derived2 item) { return ADerived2SpecificPredicate; } This pattern is called MultipleDispatch, while calling a method by reflection is slower than calling the method directly (it won't be an overhead if the method is called less than few hundred times per second), it has the benefit of not requiring to modify your class hierarchy like in the Double Dispatch pattern.
This will be even easier when c# 4.0 comes out with the dynamic keyword: protected bool ValidAdvert(Base item) { if (item.GetType() == typeof(Base)) throw new ThisIsAnAbstractClassException(); dynamic dynamicThis = this; return (bool)dynamicThis. ValidAdvert(item); }.
Also clever, and avoids messing with the various derived class (I wish there were only 2! ). – Ed Woodcock Feb 9 '10 at 13:37 quite notes: you need to cast to bool on the return, and method.
Invoke takes an of objects, and so craps out if you try and pass just the 1 :) Thanks though! – Ed Woodcock Feb 9 '10 at 13:43 @Ed -- I think keeping the predicate with the derived class is actually the preferred method. Storing derived class-specific logic in a base class creates a reverse coupling between the two.
I don't see this as a good thing at all. The base class shouldn't need to know anything about its derived classes. – tvanfosson Feb 9 '10 at 13:43 @Ed Thanks for pointing out these mistakes, I updated the answer.
– SelflessCoder Feb 9 '10 at 13:47 @tvanfosson If that logic is really specific to the object hierarchy, I agree that it would be cleaner to have an abstract implementation of ValidAdvert in the base class and overriding it in the derived classes. But if that logic is not strongly coupled with these objects, it can be cleaner to use the multiple dispatch and have all your logic in the same file rather than splitting it in multiple classes. – SelflessCoder Feb 9 '10 at 13:49.
A perfect place to use double dispatch: class Base { public abstract bool IsValid(IAdvertValidator validator); } class Derived1 : Base { public bool IsValid(IAdvertValidator validator) { return validator. ValidAdvert(this); } } class Derived2 : Base { public bool IsValid(IAdvertValidator validator) { return validator. ValidAdvert(this); } } interface IAdvertValidator { bool ValidAdvert(Derived1 d1); bool ValidAdvert(Derived2 d2); }.
Clever, I like it. – Ed Woodcock Feb 9 '10 at 13:23 A reasonable use of the pattern. An alternative would be to expose validation methods from the validator and make use them inside an implementation of IsValid, keeping the actual validation flow of control in the class.
– tvanfosson Feb 9 '10 at 13:33.
Yes, it is always one of the derived classes, however, it's also technically the base class, meaning the base class method gets called when I do (List)i. Where(ValidateAdvert), for example. – Ed Woodcock Feb 9 '10 at 13:26 Ah -- I was reading your code sample, not your question.
You don't actually want it to throw an exception, you want it to call one of the other methods instead. In that case I'd go with @Anton's suggestion, or something similar. Note that you could provide the validator in a constructor so that you don't need to pass it as an argument.
I've also used a static validation class that validates simple properties removing the need to keep a reference to it. You need to be careful with these, though, as they can make testing harder if you're not careful. – tvanfosson Feb 9 '10 at 13:40 The validator is very much a page- and status-specific class, and so wouldn't work nicely as a static, however I think it'd go quite nicely in the reflection method, it's a shame this isn't supported by default though!
– Ed Woodcock Feb 9 '10 at 13:42.
I'm not sure exactly how you will ever have an instance of the base class that isn't actually an instance of a derived class. Since the base class is abstract, it can't be instantiated. I suppose it would match any derived class that doesn't have a specific signature, but that doesn't seem to be what you're going for.
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.