【问题标题】:interface property copy in c#c#中的接口属性复制
【发布时间】:2009-08-13 15:55:00
【问题描述】:

我已经使用 C# 很多年了,但只是遇到了一个让我很困惑的问题,我什至不知道如何提出这个问题,所以,举个例子!

public interface IAddress
{
  string Address1 { get; set; }
  string Address2 { get; set; }
  string City { get; set; }
  ...
}

public class Home : IAddress
{
  // IAddress members
}

public class Work : IAddress
{
  // IAddress members
}

我的问题是,我想将 IAddress 属性的值从一个类复制到另一个类。这是否可以在一个简单的单行语句中实现,还是我仍然需要对每个语句进行属性到属性的分配?实际上,我很惊讶这个看似简单的事情却像它一样难住了我......如果不能以简洁的方式实现,那么有没有人可以使用任何捷径来做这种事情?

谢谢!

【问题讨论】:

标签: c# interface


【解决方案1】:

这是一种与接口无关的方法:

public static class ExtensionMethods
{
    public static void CopyPropertiesTo<T>(this T source, T dest)
    {
        var plist = from prop in typeof(T).GetProperties() where prop.CanRead && prop.CanWrite select prop;

        foreach (PropertyInfo prop in plist)
        {
            prop.SetValue(dest, prop.GetValue(source, null), null);
        }
    }
}

class Foo
{
    public int Age { get; set; }
    public float Weight { get; set; }
    public string Name { get; set; }
    public override string ToString()
    {
        return string.Format("Name {0}, Age {1}, Weight {2}", Name, Age, Weight);
    }
}

static void Main(string[] args)
{
     Foo a = new Foo();
     a.Age = 10;
     a.Weight = 20.3f;
     a.Name = "Ralph";
     Foo b = new Foo();
     a.CopyPropertiesTo<Foo>(b);
     Console.WriteLine(b);
 }

在您的情况下,如果您只想复制一组接口属性,您可以这样做:

((IAddress)home).CopyPropertiesTo<IAddress>(b);

【讨论】:

  • 您可能应该在此处设置一个约束 - 其中 T : IAddress.然后,您还可以缓存反射查找,而不是为每次调用都进行缓存,并且仍然避免在接口更改时需要更新方法。
  • 顺便说一句,我知道您正在尝试更一般的情况,但在这种情况下,它似乎是在尝试使用大锤敲钉子。
  • 如果sourcedest 是不同类型(它们在原始问题中),您的代码将在运行时中断。您可以通过从T 而不是从source 获取属性列表来修复它。例如:var plist = from prop in typeof(T).GetProperties() where prop.CanRead &amp;&amp; prop.CanWrite select prop;
  • @Joel - 除非您想编写特定于 IAddress 的版本,否则您不需要约束。使用时的专业化会为您解决这个问题。看起来就像是一把大锤敲钉子,但这掩盖了代码在面对不断变化的接口时的健壮性——我已经失去了足够的时间来追踪这类错误中的错误,如果我有反思,我更喜欢它从本质上消除这类错误。
【解决方案2】:

你可以构建一个扩展方法:

public static void CopyAddress(this IAddress source, IAddress destination)
{
    if (source is null) throw new ArgumentNullException("source");
    if (destination is null) throw new ArgumentNullException("destination");

    //copy members:
    destination.Address1 = source.Address1;
    //...
}

【讨论】:

  • 我真的很喜欢这个解决方案。谢谢!
  • 请参阅下面的响应,该响应具有通用扩展方法,当接口更改或添加/删除设置/获取方法时不会脆弱。
【解决方案3】:

Jimmy Bogard 的AutoMapper 对于这种映射操作非常有用。

【讨论】:

  • Apache Commons 有一个名为“BeanUtils”的库,我在使用 Java 开发时经常使用它。 Martinho Fernandes 建议的似乎是最接近的相应 .net 库。
【解决方案4】:

没有一个单一的衬里。

如果你经常这样做,你可以研究某种形式的代码生成,也许使用 T4 模板和反射。

BTW COBOL 对此有一个声明:将相应的家搬到工作岗位。

【讨论】:

    【解决方案5】:

    我不相信有一个语言准备好的解决方案(所有属性都需要有 getter 和 setter)。

    您可以使用 Copy(Address add) 方法将 Address 创建为抽象类。

    或者,您可以让 Home 和 Work 拥有一个 IAddress,而不是扩展一个。副本将立即生效。

    【讨论】:

      【解决方案6】:

      您需要创建一个方法来执行此操作

      public void CopyFrom(IAddress source)
      {
          this.Address1 = source.Address1;
          this.Address2 = source.Address2;
          this.City = source.city;
      }
      

      【讨论】:

      • 这是一个脆弱的方法,如果添加了新属性,可能会崩溃。
      • 是的,大多数方法,除非你使用反射。做用户正在谈论的事情是一个有效的选择。
      【解决方案7】:

      您可以在每个类上都有一个构造函数,采用 IAddress 并在其中填充实现的成员。

      例如

      public WorkAddress(Iaddress address)
      {
          Line1 = IAddress.Line1;
          ...
      }
      

      为了可维护性,使用反射来获取属性名称。

      HTH,

      【讨论】:

        【解决方案8】:

        如果您将家庭和工作地址的公共部分封装到一个单独的类中,可能会使您的生活更轻松。然后,您可以简单地复制该属性。这对我来说似乎是更好的设计。

        或者,您可以将一个具有反射和属性的解决方案组合在一起,其中一个对象中的属性值被复制到另一个对象中的匹配(和标记)属性。当然,这也不会是单线解决方案,但如果您拥有大量属性,它可能会比其他解决方案更快且更易于维护。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-06-16
          • 1970-01-01
          • 2011-10-13
          • 1970-01-01
          • 2013-12-31
          • 2015-08-28
          • 1970-01-01
          相关资源
          最近更新 更多