是否可以投射物体图?

时间:2009-10-13 07:26:38

标签: c# casting

我有一个像这样设置的对象图

Clients
    string Name
    List[Address] Addresses

我想把它转换为

MyClients: Clients
    string Name
    List[MyAddress] Addresses

MyAddress: Address
    String City

我知道我可以通过遍历整个对象图并在给定的示例中将其转换为不坏的。但是如果你有一个大的对象图,那么它会很快变得毛茸茸;其次,走完整个对象图似乎是完全错误的。

我正在寻找解决方案

  • 不修改客户端或地址对象
  • 不走对象图
  • 只需很少的代码更改即可实现。

  • 8 个答案:

    答案 0 :(得分:3)

    对不起,AFAIK如果没有用我所知道的语言遍历图表,就不可能进行这样的转换。

    对于忽略此要求的简单解决方案,请考虑使用Automapper(假设您使用.NET;如果没有,请指定您开发的平台)

    答案 1 :(得分:1)

    您可以为图形创建一个包装类,它可以根据需要遍历对象图形(可能需要对新创建的对象进行一些缓存)。

    请注意,这不是强制转换,但您只需在需要时创建类的新实例,例如:

    public class InitialGraph : IGraph
    {
         IEnumerable<Client> GetClients()
         {
             ...
         }
    }
    

    然后你像这样包装它:

    public class MyGraph : IGraph
    {
         private readonly IGraph _initial;
         public MyGraph(IGraph initial)
         {
             _initial = initial;
         }
    
         IEnumerable<Client> GetClients()
         {
              foreach (Client c in _initial.GetClients())
                  yield return new MyClient(c);
         }
    }
    

    您的MyClient实例将在访问时创建(延迟初始化)。

    <强> [编辑]

    实际上,由于您的新图表应该包含不同的对象(不是从客户端派生的),因此GetClients()方法无法返回IEnumerable<Client>,但是:

    // note that this class doesn't implement IGraph anymore
    public class MyGraph
    {
         private readonly IGraph _initial;
         public MyGraph(IGraph initial)
         {
             _initial = initial;
         }
    
         IEnumerable<MyClient> GetClients()
         {
              foreach (Client c in _initial.GetClients())
                  yield return new MyClient(c);
         }
    }
    

    答案 2 :(得分:1)

    序列化和XSLT可能会有所帮助,但这可能涉及到对象图的行走(可能多次)。

    答案 3 :(得分:1)

    在原始问题的评论中,您说:

      

    演员阵容的原因是   对象图在应用程序A中开始   对象图被序列化了   传递到appliaction B或应用程序   C.应用B和C扩展了   对象图为了自己的目的。   应用程序A不知道   申请B或C或什么申请   B和C正在对对象图进行操作。   应用B和C非常广泛   不同的应用程序

    然而在问题中你说的是一个很好的解决方案:

      

    不修改客户端或地址   对象

    强制转换无法为对象添加功能。该对象必须具备这些功能。

    所以听起来你不想改变类型,你只想在解决方案的某些区域为这些类型添加额外的设施。

    所以你需要extension methods

    您会保留ClientAddress类型,但可以通过扩展方法添加其他设施:

    public static class MyExtensions
    {
        public static void SendLetter(this Address address, string messageBody)
        {
            // blah
        }
    }
    

    这允许你写:

    someClient.Addresses[0].SendLetter("Dear Sir, K THX BAI");
    

    您可能需要存储额外数据以及每个Address对象。可能最方便的现成解决方案是使Address派生自DependencyObject,这允许您使用DependencyProperty的实例作为关键字存储额外数据:< / p>

    public static class MyExtensionsWithData
    {
        // declare one of these for each "data slot" you'll be using
        public static readonly DependencyProperty PhoneProperty = 
            RegisterAttached("PhoneNumber", 
                             typeof(string), 
                             typeof(MyExtensionsWithData));
    
        public static void SetPhoneNumber(this Address address, string phone)
        {
            address.SetValue(PhoneProperty, phone);
        }
    
        public static string GetPhoneNumber(this Address address)
        {
            return (string)address.GetValue(PhoneProperty);
        }
    }
    

    这样,您可以有效地向现有对象添加新属性,并可以像这样使用它们:

    // set
    someClient.Addresses[0].SetPhoneNumber("5550945793847");
    
    // get
    string phoneNum = someClient.Addresses[0].GetPhoneNumber();
    

    答案 4 :(得分:0)

    var myclients = clients.OfType(typeof(MyClients))
    

    救援的一点点LINQ: - )

    答案 5 :(得分:0)

    考虑到你的点数,答案是:否。

    为什么不在制作图表时创建正确的对象?

    答案 6 :(得分:0)

    当你使用这些对象时,你不能只是投射它们吗?

    答案 7 :(得分:0)

    将更多通用对象转换为更多特定对象并不会直接生效。

    您无法将Client投射至MyClient,但可以将MyClient投射至Client