- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我需要将属性的值从一个类复制到另一个类,它们是同一基类型的后代。源对象和目标对象可能位于同一继承分支的不同级别,这意味着一个继承自另一个,或者是不同分支的后代,这意味着它们共享一个公共(public)基类型。
A
B1 B2
C1 C2 C3
从上面的结构中,我可能想要将所有属性从 A 复制到 C1,从 C2 复制到 C3,从 C3 复制到 B1,等等。基本上是树中任何可能的组合。显然,我只能复制源类型中存在的属性,这些属性也必须存在于目标类型中。
迭代源类型的属性很容易
var sourceProperties = source.GetType().GetProperties();
但是,如何检查目标类型上声明了哪个属性?仅仅通过名称检查是不够的,因为它们可能有不同的类型。同样在过去,我使用 new
对重复属性进行了糟糕的体验。
不幸的是,C# 或 .NET 没有内置方法来检查类型是否具有特定的 PropertyInfo
,例如 Type.HasProperty(PropertyInfo)
。我能想到的最好办法是检查该属性是否由共享基类型声明。
public static void CopyProperties(object source, object target)
{
var targetType = target.GetType();
var sharedProperties =source.GetType().GetProperties()
.Where(p => p.DeclaringType.IsAssignableFrom(targetType));
foreach (var property in sharedProperties)
{
var value = property.GetValue(source);
if (property.CanWrite)
property.SetValue(target, value);
}
}
问题:有没有更好的解决方案?
最佳答案
这是一个不需要继承的解决方案。只要名称和类型匹配,它将属性从一个对象(一种类型)复制到另一个对象(另一种类型)。
您为每对您希望能够复制自/复制到的类型创建一个这些属性复制器对象的实例。 copier 对象一旦创建就不可变,因此它可以是长期存在的、静态的、可从多个线程(创建后)使用等。
这是 PropertyCopier 类的代码。创建此类对象时需要指定源类型和目标类型。
public class PropertyCopier<TSource, TDest> where TSource : class where TDest : class
{
private List<PropertyCopyPair> _propertiesToCopy = new List<PropertyCopyPair>();
public PropertyCopier()
{
//get all the readable properties of the source type
var sourceProps = new Dictionary<string, Tuple<Type, MethodInfo>>();
foreach (var prop in typeof(TSource).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (prop.CanRead)
{
sourceProps.Add(prop.Name, new Tuple<Type, MethodInfo>(prop.PropertyType, prop.GetGetMethod()));
}
}
//now walk though the writeable properties of the destination type
//if there's a match by name and type, keep track of them.
foreach (var prop in typeof(TDest).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (prop.CanWrite)
{
if (sourceProps.ContainsKey(prop.Name) && sourceProps[prop.Name].Item1 == prop.PropertyType)
{
_propertiesToCopy.Add (new PropertyCopyPair(prop.Name, prop.PropertyType, sourceProps[prop.Name].Item2, prop.GetSetMethod()));
}
}
}
}
public void Copy(TSource source, TDest dest)
{
foreach (var prop in _propertiesToCopy)
{
var val = prop.SourceReader.Invoke(source, null);
prop.DestWriter.Invoke(dest, new []{val});
}
}
}
它依赖于一个看起来像这样的帮助程序类(这可以被精简;额外的属性可以帮助调试(并且可能对您有用))。
public class PropertyCopyPair
{
public PropertyCopyPair(string name, Type theType, MethodInfo sourceReader, MethodInfo destWriter)
{
PropertyName = name;
TheType = theType;
SourceReader = sourceReader;
DestWriter = destWriter;
}
public string PropertyName { get; set; }
public Type TheType { get; set; }
public MethodInfo SourceReader { get; set; }
public MethodInfo DestWriter { get; set; }
}
我还创建了另一个真正简单的测试类:
public class TestClass
{
public string PropertyName { get; set; }
public Type TheType { get; set; }
public string Other { get; set; }
}
所有这些都准备就绪后,这段代码将执行复印机类:
var copier = new PropertyCopier<PropertyCopyPair, TestClass>();
var source = new PropertyCopyPair("bob", typeof(string), null, null);
var dest = new TestClass {Other = "other", PropertyName = "PropertyName", TheType = this.GetType()};
copier.Copy(source, dest);
当您运行它时,所有在目标中具有相同名称和类型的属性的源属性都将被复制。
如果要将源类型和目标类型限制为公共(public)基类,可以这样做:
public class PropertyCopierCommonBase<TSource, TDest, TBase> : PropertyCopier<TSource, TBase>
where TBase : class where TSource : class, TBase where TDest : class, TBase
{ }
如果您不需要两个类,只需使用上面的三个类型参数和那组通用约束声明原始 PropertyCopier
类即可。
关于C# 查找同一层次结构的两种类型共享的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51444920/
我目前正在尝试基于哈希表构建字典。逻辑是:有一个名为 HashTable 的结构,其中包含以下内容: HashFunc HashFunc; PrintFunc PrintEntry; CompareF
如果我有一个指向结构/对象的指针,并且该结构/对象包含另外两个指向其他对象的指针,并且我想删除“包含这两个指针的对象而不破坏它所持有的指针”——我该怎么做这样做吗? 指向对象 A 的指针(包含指向对象
像这样的代码 package main import "fmt" type Hello struct { ID int Raw string } type World []*Hell
我有一个采用以下格式的 CSV: Module, Topic, Sub-topic 它需要能够导入到具有以下格式的 MySQL 数据库中: CREATE TABLE `modules` ( `id
通常我使用类似的东西 copy((uint8_t*)&POD, (uint8_t*)(&POD + 1 ), back_inserter(rawData)); copy((uint8_t*)&PODV
错误 : 联合只能在具有兼容列类型的表上执行。 结构(层:字符串,skyward_number:字符串,skyward_points:字符串)<> 结构(skyward_number:字符串,层:字符
我有一个指向结构的指针数组,我正在尝试使用它们进行 while 循环。我对如何准确初始化它并不完全有信心,但我一直这样做: Entry *newEntry = malloc(sizeof(Entry)
我正在学习 C,我的问题可能很愚蠢,但我很困惑。在这样的函数中: int afunction(somevariables) { if (someconditions)
我现在正在做一项编程作业,我并没有真正完全掌握链接,因为我们还没有涉及它。但是我觉得我需要它来做我想做的事情,因为数组还不够 我创建了一个结构,如下 struct node { float coef;
给定以下代码片段: #include #include #define MAX_SIZE 15 typedef struct{ int touchdowns; int intercepti
struct contact list[3]; int checknullarray() { for(int x=0;x<10;x++) { if(strlen(con
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Empty “for” loop in Facebook ajax what does AJAX call
我刚刚在反射器中浏览了一个文件,并在结构构造函数中看到了这个: this = new Binder.SyntaxNodeOrToken(); 我以前从未见过该术语。有人能解释一下这个赋值在 C# 中的
我经常使用字符串常量,例如: DICT_KEY1 = 'DICT_KEY1' DICT_KEY2 = 'DICT_KEY2' ... 很多时候我不介意实际的文字是什么,只要它们是独一无二的并且对人类读
我是 C 的新手,我不明白为什么下面的代码不起作用: typedef struct{ uint8_t a; uint8_t* b; } test_struct; test_struct
您能否制作一个行为类似于内置类之一的结构,您可以在其中直接分配值而无需调用属性? 前任: RoundedDouble count; count = 5; 而不是使用 RoundedDouble cou
这是我的代码: #include typedef struct { const char *description; float value; int age; } swag
在创建嵌套列表时,我认为 R 具有对列表元素有用的命名结构。我有一个列表列表,并希望应用包含在任何列表中的每个向量的函数。 lapply这样做但随后剥离了列表的命名结构。我该怎么办 lapply嵌套列
我正在做一个用于学习目的的个人组织者,我从来没有使用过 XML,所以我不确定我的解决方案是否是最好的。这是我附带的 XML 文件的基本结构:
我是新来的 nosql概念,所以当我开始学习时 PouchDB ,我找到了这个转换表。我的困惑是,如何PouchDB如果可以说我有多个表,是否意味着我需要创建多个数据库?因为根据我在 pouchdb
我是一名优秀的程序员,十分优秀!