我有大量自动生成的对象。尽管它们都是不同的非相关类,但所有对象都共享一些基本属性(名称,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;
}
虽然自然这不起作用。
我认为通用方法可能会有答案,但我能看到用当前类型调用它的唯一方法是使用genericMethod.Invoke
,它仍然存在无法解析属性的问题方法中传递的对象。这与Calling generic method with a type argument known only at execution time或How to call generic method with a given Type object?不同,{{3}}或{{3}}在方法中仅使用类型的类型或属性,而不是对象的属性。
我知道这会(非常)容易出错,但我可以保证遇到的所有对象都会被操纵的公共属性。
答案 0 :(得分: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}";
}
}
答案 1 :(得分:2)
如果你对D Stanley提到的使用动态的表现不满意,你可以随时尝试FastMember。
前两个代码示例中显示了开始使用它所需要的所有内容。
答案 2 :(得分:0)
您正在那里创建Rube Goldberg设备。您应该让所有数据对象类都实现单个接口,然后您就可以开始工作了。比摆弄反射更简单,更容易出错。
很多对象具有共同属性但不共享相同的祖先这一事实,至少在一个通用接口上,表明你的设计出了问题。重新考虑一下。
答案 3 :(得分:0)
实现这一目标的多种方法,最简单的可能是创建接口并在那里声明常用方法,让你的对象实现它,然后改变“getName”方法取接口对象
private string getName(IMyInterface anyObjWithName)
{
return anyObjWithName.name;
}
答案 4 :(得分: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);
}
}
答案 5 :(得分: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);