views:

78

answers:

3

I have the methods:

public MyReturnType MyMethod(Class1 arg)
{
 //implementation
}

public MyReturnType MyMethod(Class2 arg)
{
 //implementation
}

//...

public MyReturnType MyMethod(ClassN arg)
{
 //implementation
}

decimal, string, DateTime in [Class1, ... , ClassN]
and one common method:

public MyReturnType MyMethod(object obj)
{
 if(obj == null)
  throw new ArgumentNullException("obj");
 if(obj is MyClass1)
  return MyMethod((Class1)obj);
 if(obj is MyClass2)
  return MyMethod((Class2)obj);
 //...
 if(obj is MyClassN)
  return MyMethod((ClassN)obj);
 return MyMethod(obj.ToString()); //MyMethod(string) implemented.
}

How can i refactor this code? I can use attributes and component model, something like this:

public class MyAttribute : Attribute
{
 public Type Type { get; set; }
}

public MyReturnType MyMethod(object obj)
{
    if(obj == null)
        throw new ArgumentNullException("obj");
 var protperty = TypeDescriptor.GetProperties(this, new Attribute[] { new MyAttribute() })
  .Cast<PropertyDescriptor>().FirstOrDefault(x =>
   x.GetAttribute<MyAttribute>().Type.IsInstanceOfType(obj));
 if (protperty != null)
  return protperty.GetValue(obj) as MyReturnType;
 return MyMethod(obj.ToString());
}

but it looks quite hard to understand and can create some bugs. For example if somebody declare method like

[MyAttribute(Type = ClassNplus1)]
public NotMyReturnType MyMethod(ClassNplus1 arg);

Any other ideas how to create extensible system, where adding new class is required only to add one method? (add code in one place)

A: 

You could use Generics and Attributes to describe some kind of meta data about the class The Generics will most likely clean up your if statements

Hmmm...

public class MyClass<T>
{
   public OtherClass ReturnSomething(T checkThisType)
   {
   }
}

Sorry I could be more descriptive. I hope this helps.

PieterG
+1  A: 

I believe what you are trying to do is known as multiple dispatch (someone please correct me if I'm wrong) and this is not available in current versions of the .Net framework. However it is being introduced in .Net 4.0 via the dynamic keyword -> http://blogs.msdn.com/laurionb/archive/2009/08/13/multimethods-in-c-4-0-with-dynamic.aspx.

mattythomas2000
Yes, this is looks like what i am looking for, but i can use 3.5 framework. Is it possible to simulate it?thanks for the link.
Steck
I've not implemented this pattern myself but when talking to colleagues a common away around this is to use the double dispatch pattern. It's described here -> http://www.garyshort.org/blog/archive/2008/02/11/double-dispatch-pattern.aspx. Hope this helps
mattythomas2000
+4  A: 

Sounds like you need to use generic methods:

public MyReturnType MyMethod<T>(T arg)
{
    // implementation
}

The nice thing here is that you can also restrict T like so:

public MyReturnType MyMethod<T>(T arg) where T : MyClassBase
{
    // implementation
}

In the second case, you can treat T as if it was an actual MyClassBase, but you're free to pass in any object, as long as it is (or derives from) MyClassBase. This also works for interfaces as well.

You call this method like so:

MyMethod(new MyClass1());
MyMethod(new MyClass2());
MyMethod(new MyClass3());

The compiler is smart enough to know which type it is so you don't have to pass it the type of T, but sometimes you need to explicitly declare it when calling the method, like so:

MyMethod<MyClass1>(new MyClass1());
MyMethod<MyClass2>(new MyClass2());
MyMethod<MyClass3>(new MyClass3());
Daniel T.
My code also called from property descriptors, so MyMethod(object) or some manager to resolve correct type is required.This question can be reduced to the question of writing the manager.
Steck
By 'property descriptors', are you talking about attributes? What are you trying to do with the code? There may be a design problem.
Daniel T.