views:

385

answers:

6

To cut a long story short I have a C# function that performs a task on a given Type that is passed in as an Object instance. All works fine when a class instance is passed in. However, when the object is declared as an interface I'd really like to find the concrete class and perform the action upon that class type.

Here is the ubiquitous bad example (resplendent with incorrect property casing etc):

public interface IA
{
    int a { get; set; }
}
public class B : IA
{
    public int a { get; set; }
    public int b { get; set; }
}
public class C : IA
{
    public int a { get; set; }
    public int c { get; set; }
}

// snip

IA myBObject = new B();
PerformAction(myBObject);

IA myCObject = new C();
PerformAction(myCObject);

// snip

void PerformAction(object myObject)
{
    Type objectType = myObject.GetType();   // Here is where I get typeof(IA)
    if ( objectType.IsInterface )
    {
        // I want to determine the actual Concrete Type, i.e. either B or C
        // objectType = DetermineConcreteType(objectType);
    }
    // snip - other actions on objectType
}

I'd like the code in PerformAction to use Reflection against it's parameter and see that it's not just an instance of IA but that it's an instance of B and to see the property "b" via GetProperties(). If I use .GetType() I get the Type of IA - not what I want.

How can PerformAction determine the underlying Concrete Type of the instance of IA?

Some might be tempted to suggest using an Abstract class but that is just the limitation of my bad example. The variable will be originally declared as an interface instance.

+3  A: 

You can never have instances of an Interface. So determining whether you are dealing with an interface or a concrete type is not possible since you will always be dealing with a concrete type. So I am not sure you question makes any sense. What exactly are you trying to do and why?

Chris Johnston
+1 exactly, in fact his example works fine.
Stan R.
+2  A: 

What are you doing is really bed design but you don't have to use reflection you can check it like this

void PerformAction(object myObject)
{
    B objectType = myObject as B;   // Here is where I get typeof(IA)
    if ( objectType != null )
    {
        //use objectType.b
    }
    else
    {
       //Same with A 
    }
    // snip - other actions on objectType
}
ArsenMkrt
This is still fairly bad design, as you are still dependant on the concrete type. This largely defeats the purpose of having an interface in the first place...
jrista
+4  A: 
Type objectType = myObject.GetType();

Should still give you the concrete type, according to your example. So i don't see your problem.

Stan R.
Yes, the calling "myObject.GetType()" wil NEVER returns interface type.
TcKs
A: 

Maybe you are looking for the is operator

void PerformAction(object myObject)
{
    if (myObject is B)
    {
        B myBObject = myObject as B;
     myBObject.b = 1;
    }

    if (myObject is C)
    {
     C myCObject = myObject as C;
     myCObject.c = 1;
    }

    // snip - other actions on objectType
}
kova
+1  A: 

I have to agree about the bad design. If you have an interface, it should be because you need to utilize some common functionality without caring what the concrete implementation is. Given you're example, it sounds like the PerformAction method should actually be a part of the interface:

public interface IA
{
    int a { get; set; }
    void PerformAction();
}

public class B: IA
{
    public int a { get; set; }
    public int b { get; set; }

    public void PerformAction()
    {
        // perform action specific to B
    }
}

public class C : IA
{
    public int a { get; set; }
    public int c { get; set; }

    public void PerformAction()
    {
        // perform action specific to C
    }
}

void PerformActionOn(IA instance)
{
    if (instance == null) throw new ArgumentNullException("instance");

    instance.PerformAction();

    // Do some other common work...
}


B b = new B();
C c = new C();

PerformActionOn(b);
PerformActionOn(c);
jrista
A: 

As I'm not a member and I can't log in I don't know how to "select" the right answer. I also can't add any comments. If I have another question I'll sign up.

Basically, my very contrived example was always going to draw criticism of bad design - and as it stands it's awful. So fair comments all round.

However, I posted the question at home (late at night) and now I'm back at work I can see my glaring mistake. It was Stan R that put me on the right path so +1 Stan.

The type I was getting was not from calling GetType but it was the FieldType property from FieldInfo. Seeing as I was calling GetValue anyway I can call GetType on the result (so long as it is not null).

To make more sense, we are converting a large dinosaur-language client-server app into dotNet. We have a conversion for the screen layouts and the code syntax. We have over a thousand screens with 8000 separate places where SQL is run and we are trying to deal with the embedded bind variables in the SQL. Seeing as management don't want to spend the extra money to manually rewrite those sections we are looking for the "cheap out" - for example:

select colA, colB from Table into :varA, :varB.varC where colD = :varD

I am pre-parsing the SQL to strip out the into clause and replace ":varD" with it's value. I have a mechanism to make sure I look in the right places for the variables. On fetching, varA and varB.varC will get the values "automagically". This is where I need reflection and also shows how bad my example was.

Anyway, Stan R's comment was the "smack over the back of the head" that I needed. There was a nice simple solution - it's not always perfect due to nulls. However, if varB is null you aren't getting a value into varB.varC anyway. However, the conversion is written such that classes are automatically instantiated. Ongoing development is another issue... :-)

So far as I'm concerned this is solved. Thanks everyone for taking the time to respond.