MaxPRafferty
MaxPRafferty

Reputation: 4977

Method to handle objects with properties in common, but different object types

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.

Upvotes: 5

Views: 3422

Answers (6)

cookie
cookie

Reputation: 79

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.

Upvotes: 2

D Stanley
D Stanley

Reputation: 152596

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}";
    }
}

Upvotes: 9

ispiro
ispiro

Reputation: 27703

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);

Upvotes: 0

user2599849
user2599849

Reputation:

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);
    }
}

Upvotes: 0

Konstantin
Konstantin

Reputation: 3294

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;
}

Upvotes: 0

Geeky Guy
Geeky Guy

Reputation: 9399

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.

Upvotes: 0

Related Questions