5

我有大量自动生成的对象。尽管它们都是不同的、不相关的类,但所有对象都共享一些基本属性(名称、id 等)。我不控制这些对象的生成,所以很遗憾我无法采用理想的方法来实现接口。我想创建一个方法,在该方法中我传递任意一个这些对象并使用这些公共属性做一些事情。

一般的想法是这样的:

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

虽然这自然是行不通的。

我认为一个泛型方法可能有答案,但我能看到用当前类型调用它的唯一方法是 using genericMethod.Invoke,它仍然存在无法解析方法中传递对象的属性的相同问题。这与使用仅在执行时已知的类型参数调用泛型方法如何使用给定的 Type 对象调用泛型方法不同?在方法中只使用类型或类型的属性,而不是对象的属性。

我知道这将(非常)容易出错,但我可以保证遇到的所有对象都将具有被操纵的公共属性。

4

6 回答 6

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}";
    }
}
于 2013-08-12T19:59:59.193 回答
2

如果您对 D Stanley 提到的使用动态的性能不满意,您可以随时尝试FastMember

开始使用它所需的所有知识都在前 2 个代码示例中显示。

于 2013-08-12T20:27:10.883 回答
0

您正在那里创建一个 Rube Goldberg 设备。您应该只让所有数据对象类实现一个接口,然后您就可以使用它。比摆弄反射更简单,更不容易出错。

许多对象具有共同的属性但不具有相同的祖先,至少在一个共同的界面上,这一事实表明您的设计有问题。重新考虑一下。

于 2013-08-12T20:01:08.547 回答
0

有多种方法可以做到这一点,最简单的可能是创建接口并在那里声明常用方法,让你的对象实现它,然后更改“getName”方法获取接口对象

private string getName(IMyInterface anyObjWithName)
{
    return anyObjWithName.name;
}
于 2013-08-12T20:04:42.130 回答
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);
    }
}
于 2013-08-12T20:05:06.360 回答
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);
于 2013-08-12T20:06:06.630 回答