5

I have a large collection of automatically generated objects. Although they are all of different, non-related classes, all of the objects share some basic properties (name, id, etc.). I do not control the generation of these objects, so unfortunately I cannot take the ideal approach of implementing an interface. I would like to create a method in which I pass an arbitrary one of these objects and do something using these common properties.

The general idea would be something like:

someObj a = new someObj();
a.name = "sara";
diffObj b = new diffObj();
b.name = "joe";
string phrase = string.Format("I am with {0} and {1}", 
    getName(a), getName(b));

private string getName(object anyObjWithName)
{
    return anyObjWithName.name;
}

though naturally this does not work.

I thought a generic method might hold the answer, but the only way I can see to call it with the current type is using genericMethod.Invoke , which still carries the same issue of not being able to resolve the properties of the passed object in the method. This is unlike Calling generic method with a type argument known only at execution time or How to call generic method with a given Type object? where only the type, or properties of the type, are used in the method, as opposed to properties of the object.

I am aware that this would be (very) prone to error, but I can guarantee that all objects encountered will have the common properties being manipulated.

3
  • Try either declaring an interface to relate the objects for common properties, or use reflection. Commented Aug 12, 2013 at 20:01
  • 1
    msdn.microsoft.com/en-us/library/64syzecx.aspx Commented Aug 12, 2013 at 20:01
  • 1
    Ah, perhaps I need to be more clear. I am unable to use good OOP practice and implement an interface because of the way my objects are generated. I do not control this process, unfortunately. Commented Aug 12, 2013 at 20:07

6 Answers 6

9

I can guarantee that all objects encountered will have the common properties being manipulated

If that's the case, you can use dynamic:

private string getName(dynamic anyObjWithName)
{
    return anyObjWithName.name;
}

Be aware that using any object that does not have a name property will not fail until run-time.

If you want to add a little bit of safety you can catch the RuntimeBinderException that gets thrown if the property does not exist:

private string getName(dynamic anyObjWithName)
{
    try {
        return anyObjWithName.name;
    }
    catch(RuntimeBinderException) {
        return "{unknown}";
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

For my $.02, I don't think that the OP is in a position to begin the dynamic path. The road is fraught with danger and this answer is not pedagogical at all.
I knew i was in for some pain going into it. As I cannot implement an interface, I'm not sure there is another option.
Please edit your question with this constraint in big bold letters or many others might go with the dynamic solution when an interface is available to them.
@MaxPRafferty This is only from .net 4.0 and up as far as I know.
@KeithPayne Updated! Thanks for the heads up.
|
2

If you're unhappy with the performance using dynamic as mentioned by D Stanley, you could always try FastMember.

All you need to know to start using it is pretty much shown in the first 2 code examples.

2 Comments

Wow, yeah, this library literally exists to solve this exact problem. I wonder how it does it under the hood without reflection...
@MaxPRafferty: IIRC, it will leverage reflection to get the member information the first time, write equivalent compile-time IL, then used that compiled code for subsequent access to that type/member. This gives it speed closer to compiled code when compared against frequently hitting the DLR or reflection.
0

You are creating a Rube Goldberg device there. You should just have all your data objects classes implement a single interface, then you can work on that. Much simpler and less error prone than fiddling with reflection.

The very fact that a lot of objects have common properties but don't share the same ancestry, on in the very least a common interface, shows that something is wrong with your design. Do rethink it.

1 Comment

That's really where the problem comes in - I don't control the generation of the objects. My kingdom for an interface!
0

Multiple ways to accomplish this, simplest probably is to create Interface and declare common methods there, have your object implement it, then change "getName" method take interface object

private string getName(IMyInterface anyObjWithName)
{
    return anyObjWithName.name;
}

Comments

0

The correct way to do this is with an interface, if you own the types that you're working with

public interface IEntity
{
    int ID { get; set; }
    string Name { get; set; }
}

public class TypeOne : IEntity
{
    public int ID { get; set; }
    public string Name { get; set }

    public string BespokePropertyOne { get; set;}
}

public class TypeTwo : IEntity
{
    public int ID { get; set; }
    public string Name { get; set; }

    public float BespokePropertyTwo { get; set; }
}

static void Main(string[] args)
{
    List<IEntity> entities = new List<IEntity>();
    entities.Add(new TypeOne() { ID = 1, Name = "Bob", BespokePropertyOne = "blablabla" });
    entities.Add(new TypeTwo() { ID = 2, Name = "Alice", BespokePropertyTwo = 5.4f });

    foreach (IEntity entity in entities)
    {
        Console.WriteLine("ID: {0} Name: {1}", entity.ID, entity.Name);
    }
}

1 Comment

OP doesnt have a way to control classes. Its mentioned in question.
0

This answer was written before the edit to the question stating that interfaces weren't possible in this case. Perhaps it can help someone else reading this question.

Interface:

interface Iname
{
    string Name { get; set; }
}

Use interface:

class A : Iname
{
    public string Name { get; set; }
}

class B : Iname
{
    public string Name { get; set; }
}

The method:

string GetName(Iname o)
{
    return o.Name;
}

Use:

A a = new A { Name = "First" };
B b = new B { Name = "Last" };
Text = GetName(a) + " " + GetName(b);

1 Comment

OP doesnt have a way to control classes. Its mentioned in question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.