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.

Community
  • 1
  • 1
MaxPRafferty
  • 4,819
  • 4
  • 32
  • 39
  • Try either declaring an interface to relate the objects for common properties, or use reflection. – Nayan Aug 12 '13 at 20:01
  • 1
    http://msdn.microsoft.com/en-us/library/64syzecx.aspx – Chris Pfohl Aug 12 '13 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. – MaxPRafferty Aug 12 '13 at 20:07

6 Answers6

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}";
    }
}
D Stanley
  • 149,601
  • 11
  • 178
  • 240
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.

cookie
  • 79
  • 4
  • Wow, yeah, this library literally exists to solve this exact problem. I wonder how it does it under the hood without reflection... – MaxPRafferty Aug 12 '13 at 20:31
  • 1
    @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. – Chris Sinclair Aug 12 '13 at 20:49
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.

Geeky Guy
  • 9,229
  • 4
  • 42
  • 62
  • 2
    That's really where the problem comes in - I don't control the generation of the objects. My kingdom for an interface! – MaxPRafferty Aug 12 '13 at 20:04
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;
}
Konstantin
  • 3,254
  • 15
  • 20
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);
    }
}
Cakez0r
  • 338
  • 1
  • 9
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);
ispiro
  • 26,556
  • 38
  • 136
  • 291