【问题标题】:Initialise one object from another where they share a common interface c#从另一个对象初始化一个对象,它们共享一个公共接口 c#
【发布时间】:2017-05-08 08:01:21
【问题描述】:

我想将一个接口的实例传递给一个对象,并将这个对象的所有值初始化为传入的对象的值,其中两个对象都实现相同的接口?在这种共享界面的特殊情况下,是否有任何好的快捷方式。在我看来一定有……我只是想不起来……

编辑:在约翰的反馈之后,问题更好地表达为 - 我如何将 interface 的实例传递给对象的构造函数并将该对象的所有值初始化为接口的值实例传入?

大多数深度复制解决方案(包括我自己以前的解决方案)都返回一个对象——它不能在构造函数中工作,或者依赖于创建一个新实例(它不能使用作为源和目标的接口) )。

我想同时传入源和目标,并将源的属性复制到它们都是接口的目标。是否有现有的解决方案。或者我是否重新审视我自己的代码并尝试对其进行调整 - 我从 2009 年开始自己的解决方案(在答案中纠正了小错误)SetValue on PropertyInfo instance error "Object does not match target type" c#transfering one object properties values to another one 中的 svics 答案足以满足所有属性只是值的简单情况。

例如

    public interface ISomething
    {
        ...
    }

    public class A : ISomething
    {

        public A(ISomething input)
        {

            // what goes here??
        }
    }

【问题讨论】:

  • 不,没有 C# 功能。可能有映射库可以做到这一点,但在各种情况下,您需要提供 很多 更多信息。如果接口中既有方法又有属性怎么办?如果一个属性是一个复杂的对象怎么办——你只是喜欢复制引用,还是需要深度克隆?
  • @JonSkeet: ...如果某些属性必须按特定顺序分配(在值之前考虑最小值和最大值)怎么办?
  • 好的,我明白了。我很早就知道所有问题,并且熟悉 MiscUtil.Reflection.PropertyCopy 和类似的复制实现(包括我多年来自己的)来处理提到的所有问题。我想我的问题变得不同了。我将进行编辑以澄清。
  • 天哪,我已经完全忘记了 MiscUtil.Reflection.PropertyCopy。它当然不会尝试应对任何这些……
  • 请注意,如果您在界面中提供具体示例而不仅仅是“...”,这将是一个非常清晰的问题。

标签: c#


【解决方案1】:

我不确定我是否完全理解您的限制,但对于大多数对象复制工作,我使用 AutoMapper,它极大地帮助了复制对象的繁重工作。这意味着与在构造函数中复制属性不同的方法,但可能有用。下面是一些示例代码:

public interface ISomething {
    string MyProperty { get; set; }
    int AnotherProperty { get; set; }

    B ClassProperty { get; set; }
}

public class A : ISomething {
    public string MyProperty { get; set; }
    public int AnotherProperty { get; set; }
    public B ClassProperty { get; set; }
}

public class B {
    public string BProperty_1 { get; set; }
    public int BProperty_2 { get; set; }
}

class Program {
    static void Main(string[] args) {

        // Configure the mapping
        Mapper.Initialize(cfg => cfg.CreateMap<ISomething, ISomething>());

        // Initialize first instance
        var firstA = new A {
            MyProperty = "Test",
            AnotherProperty = 21,

            ClassProperty = new B {
                BProperty_1 = "B String",
                BProperty_2 = 555
            }
        };

        // Initialize second instance and perform the mapping
        var secondA = Mapper.Map<ISomething>(firstA);

这里,firstA 中的所有属性都复制到 secondA 中,包括 ClassProperty 中的属性。

映射配置在启动时执行一次,并使用递归和反射来构建映射模型。然后可以在代码中的任何地方使用它。如果向接口添加新属性,则映射配置保持不变。

【讨论】:

  • 我不记得上次使用 AutoMapper 时不喜欢它的地方,但它绝对是正确的“现成”解决方案。我可能会再试一次!
  • 很高兴这有帮助。对于更复杂的情况,值得深入研究 AutoMapper,但对于我所做的几乎所有事情,都有一种非常简单的方法。我花在学习上的时间在节省的时间和理智上得到了很多倍的回报。当然,在构建视图模型时,正如您在上面指出的那样,可能会有 很多 属性!
【解决方案2】:

只需在构造函数中设置接口的所有属性即可:

public class A : ISomething
{
    public A(ISomething input)
    {
        A.MyProperty = input.MyProperty;
        A.AnotherProperty = somethingNotFromTheInterface
    }
}

这称为copy-constructor。这实际上是创建现有实例的深副本还是浅副本取决于它是否包含对其他引用类型的引用。在这种情况下,您还必须重新创建所有这些实例:

    public A(ISomething input)
    {
        A.MyProperty = new MyType(input.MyProperty);
        A.AnotherProperty = somethingNotFromTheInterface
    }

它本身假设您也有一个 MyProperty 类型的复制构造函数。

当您的界面很大时,这可能会成为一项艰巨的任务。在这种情况下,您可以考虑使用反射循环所有接口属性,或者更好地重新考虑您的接口是否实际上服务于单一目的并且没有做太多事情。

【讨论】:

  • 我正在努力避免这种方法的繁琐重复,并找到一个通用的解决方案。
  • 请参阅我的最后一段。
  • 查看上面的编辑和约翰的评论。它是一个视图模型。有时只有这么多字段,而您确实想要它们:-)
  • 接口的方法是一样的。您需要一种将所有内容从一个实例复制到新实例的方法,因此要么构建一个复制构造函数,要么实现IClone-interface。但是,您仍然可以使用反射来循环所有要复制的属性。
  • 所以将这些链接放入您的问题中,以便其他人知道您已经尝试过什么。还要附上为什么这种方法不能完全满足您的需求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-30
  • 1970-01-01
  • 2014-12-08
  • 1970-01-01
  • 2019-06-13
  • 1970-01-01
  • 2020-12-05
相关资源
最近更新 更多