2013-08-12 3 views
5

У меня есть большая коллекция автоматически сгенерированных объектов. Хотя все они разные, не связанные классы, все объекты имеют общие свойства (имя, идентификатор и т. Д.). Я не управляю поколением этих объектов, поэтому, к сожалению, я не могу использовать идеальный подход к реализации интерфейса. Я хотел бы создать метод, в котором я передаю произвольный один из этих объектов и сделаю что-то, используя эти общие свойства.Метод обработки объектов со свойствами, общих для разных типов объектов

Общая идея будет что-то вроде:

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

хотя, конечно, это не работает.

Я думал, что общий метод может содержать ответ, но единственный способ увидеть его с текущим типом - использовать genericMethod.Invoke, который по-прежнему несет ту же проблему, что и не в состоянии разрешить свойства переданного объекта в методе. Это не похоже на Calling generic method with a type argument known only at execution time или How to call generic method with a given Type object?, где в этом методе используются только тип или свойства этого типа, а не свойства объекта.

Я знаю, что это было бы (очень) подвержено ошибкам, но я могу гарантировать, что все обнаруженные объекты будут иметь общие свойства, которыми манипулируют.

+5

Использовать интерфейс? – Michael

+0

Попробуйте либо объявить интерфейс для связи объектов для общих свойств, либо использовать отражение. – Nayan

+1

http://msdn.microsoft.com/en-us/library/64syzecx.aspx – Crisfole

ответ

9

Я могу гарантировать, что все объекты, встречающиеся будет иметь общие свойства манипулируют

Если это так, то вы можете использовать dynamic:

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

Имейте в виде, что с помощью какого-либо объекта, не имеет свойства name, не будет работать до выполнения.

Если вы хотите добавить немного безопасности, вы можете поймать RuntimeBinderException, что выкинут, если свойство не существует:

private string getName(dynamic anyObjWithName) 
{ 
    try { 
     return anyObjWithName.name; 
    } 
    catch(RuntimeBinderException) { 
     return "{unknown}"; 
    } 
} 
+0

Прохладный, я никогда не видел этого решения ... – ganders

+3

Для моих $ .02 я не думаю, что OP в состоянии начать «динамический путь». Дорога чревата опасностью, и этот ответ вообще не является педагогическим. –

+1

Я знал, что у меня возникла какая-то боль. Поскольку я не могу реализовать интерфейс, я не уверен, что есть другой вариант. – MaxPRafferty

0

Вы создаете устройство Руба Голдберга там. Вам просто нужно, чтобы все классы объектов данных реализовали единый интерфейс, тогда вы можете работать над этим. Гораздо проще и меньше ошибок, чем вождение с отражением.

Тот факт, что многие объекты имеют общие свойства, но не разделяют одну и ту же родословную, по крайней мере, с общим интерфейсом, показывает, что с вашим дизайном что-то не так. Пересмотрите его.

+2

Именно здесь возникает проблема - я не контролирую генерацию объектов. Мое королевство для интерфейса! – MaxPRafferty

0

несколько способов сделать это, самый простой, вероятно, является создание интерфейса и объявить общие методы там, ваш объект реализовать его, а затем изменить «GetName» объект интерфейса метод взять

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

Правильный способ сделать это является интерфейсом, если у вас есть типы, которые вы работаете с

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

OP не имеет возможности контролировать классы. Это упомянуто в вопросе. – nawfal

0

Этот ответ был написан до редактирования на вопрос о том, что интерфейсы не были возможны в этом случае. Возможно, это поможет кому-то еще прочитать этот вопрос.

Интерфейс:

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

Использование интерфейса:

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

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

Метод:

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

Использование:

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

OP не имеет возможности контролировать классы. Это упомянуто в вопросе. – nawfal

2

Если вы недовольны работой с использованием динамических функций, как упомянуто D Stanley, вы всегда можете попробовать FastMember.

Все, что вам нужно знать, чтобы начать использовать его, в значительной степени показано в первых двух примерах кода.

+0

Вау, да, эта библиотека существует буквально для решения этой точной проблемы. Интересно, как это происходит под капотом без отражения ... – MaxPRafferty

+1

@MaxPRafferty: IIRC, он будет использовать отражение, чтобы получить информацию о членах в первый раз, написать эквивалентный IL-код компиляции, затем использовать этот скомпилированный код для последующего доступа к этому тип/член. Это дает ему скорость ближе к скомпилированному коду при сравнении с тем, что часто поражает DLR или отражение. –

Смежные вопросы