通过扩展方法将一个对象转换为另一个对象 - 寻找替代解决方案

发布于 2024-11-29 16:41:53 字数 1612 浏览 6 评论 0原文

这可能是一个有点奇怪的问题,我现在所做的工作是有效的,但对我来说感觉有点奇怪,我想知道这是因为糟糕的设计/架构。如有任何想法,我们将不胜感激。

最初的设计是在我从别人那里继承的代码库中。我们有一个 linq-to-sql 类(在 dbml 的设计器文件中自动生成)。


[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.ARCustomers")]
public partial class ARCustomer : INotifyPropertyChanging, INotifyPropertyChanged
{
    // variables
    // extensibility method defs
    // ctor
    // properties
    // etc.
}

然后是另一个名为 ArCustomer 的类(请注意小写的“r”),它是自动生成的类的扩展版本。当我说扩展时,我的意思是它具有 LINQ 类的所有属性,以及一些需要一些逻辑来填充的属性。

代码中有很多地方我们想要获取 ARCustomer 并将其转换为 ArCustomer。所以我在ArCustomer类上写了一个扩展方法(这就是感觉奇怪的地方)。


public static ArCustomer FromDatacontextObject(this ArCustomer customer, ARCustomer datacontextObject)
{
    var arCustomer = new ArCustomer();
    arCustomer.Id = datacontextObject.ProjectID;
    // more of the same

    // now populate the other fields that don't exist on the datacontextObject

    return arCustomer;
}

它是这样称呼的。


var customerfromDb = accountReceivableRepository.GetCurCustomer(arId);
ArCustomer customer = new ArCustomer();
customer = customer.FromDatacontextObject(customerfromDb);

我觉得这不对,但我不知道还有什么更好的选择。 (包含扩展属性的分部类可以工作吗?将它们填充到它的构造函数中?)或者也许没关系......我对一些事情感兴趣......我觉得

  1. 这是错误/奇怪/不好的感觉是对的吗?
  2. 具体来说,我实施的解决方案有哪些缺点?我觉得其中一个原因是我经常挠头试图区分这两个类并弄清楚哪个是哪个。
  3. 他们有什么优点吗?
  4. 有更好的解决方案(以及为什么它们更好)?

(无关 - 我希望这种问题对于堆栈溢出来说是可以的。我几乎觉得我在要求进行小型代码审查,这可能是主观的;另一方面,我试图问一些具体的问题,并觉得我必须不是唯一遇到这种情况的开发人员(“我有一个对象,需要将其变成另一个对象”),所以希望通过保持线程打开可以有所收获)。

谢谢你们!

This may be a bit of an odd question, and what I have in place now works, but it feels a bit strange to me and I wonder it's because of poor design/architecture. Any thoughts here would be appreciated.

The initial design is in a code base I inherited from someone else. We have a linq-to-sql class (auto generated in the dbml's designer file).


[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.ARCustomers")]
public partial class ARCustomer : INotifyPropertyChanging, INotifyPropertyChanged
{
    // variables
    // extensibility method defs
    // ctor
    // properties
    // etc.
}

Then another class class called ArCustomer (notice the lower case "r") that is an extended version of the auto-generated class. When I say extended, I mean it has all the properies of the LINQ class, plus a few more that requires some logic to populate.

There are a lot of places in code that we want to take an ARCustomer and turn it into an ArCustomer. So I wrote an extension method (this is what felt strange) on the ArCustomer class.


public static ArCustomer FromDatacontextObject(this ArCustomer customer, ARCustomer datacontextObject)
{
    var arCustomer = new ArCustomer();
    arCustomer.Id = datacontextObject.ProjectID;
    // more of the same

    // now populate the other fields that don't exist on the datacontextObject

    return arCustomer;
}

It's called as such.


var customerfromDb = accountReceivableRepository.GetCurCustomer(arId);
ArCustomer customer = new ArCustomer();
customer = customer.FromDatacontextObject(customerfromDb);

This feels wrong to me, but I don't know of any better alternatives off the top of my head. (Would a partial class that contains the extended properties work? Populate them in it's constructor?) Or maybe it's fine... I'm interested in a few things...

  1. Am I right in feeling that this is wrong/odd/bad?
  2. Specifically, what are the cons to be found in the solution I've implemented? I feel like one is that I scratch my head too often trying to differentiate between the two classes and figure out which is which.
  3. Are their any pros?
  4. Any better solutions (and why they're better)?

(Unrelated - I hope this kind of question is OK for stack overflow. I almost feel like I'm asking for a mini code review, which can be subjective; on the other hand, I tried to ask some concrete questions and feel I must not be the only developer to have ran into a situation like this ("I have one object and need to turn it into another"), so hopefully there is something to be gained from leaving the thread open).

Thanks guys!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

临走之时 2024-12-06 16:41:53

你的直觉对你很有帮助。

从技术上讲,C# 编译器允许两个类具有相同的名称(仅大小写不同),但这是一个坏主意。此外,它也不符合 CLS。

由于您已经说过的确切原因,这是一个坏主意:可读性。不要低估可读性的重要性。就我个人而言,这是我衡量代码质量的第一个指标。可读的代码往往具有较少的错误,并且更易于调试/维护。

LINQ to SQL 生成的类已经是部分类。您可以添加单独的代码文件来定义所需的任何额外部分。而且,这是完成您所描述的内容的首选方法。更容易维护和理解。

或者,您可以创建一个包含 ARCustomer 的“ViewModel”类。 (这取决于您的架构)。

Your instincts serve you well.

Having two classes with the same name (differing only be case) is technically allowed by the C# compiler, but it is a bad idea. Also, it is not CLS compliant.

It is a bad idea for the exact reason that you already stated: readability. Don't underestimate the importance of readability. Personally it is my number one measure of code quality. Readable code tends to have fewer bugs, and is easier to debug/maintain.

The classes generated by LINQ to SQL are already partial classes. You can add a separate code file to define any extra parts that you want. And, this is the preferred method to accomplish what you are describing. It is easier to maintain and understand.

Alternatively, you could create a "ViewModel" class that contains the ARCustomer. (This depends on your architecture).

野稚 2024-12-06 16:41:53

如果您更改扩展方法来扩展数据库对象,那么您将拥有更自然的 API IMO

public static ArCustomer ToDomainObject(this ARCustomer datacontextObject)
{
   var arCustomer = new ArCustomer();
   arCustomer.Id = datacontextObject.ProjectID;
   // more of the same

   // now populate the other fields that don't exist on the datacontextObject

   return arCustomer;
}

,那么数据访问代码如下所示

var customerfromDb = accountReceivableRepository.GetCurCustomer(arId);
ArCustomer customer = customerfromDb.ToDomainObject();

If you change the extension method to extend the database object you have a more natural API IMO

public static ArCustomer ToDomainObject(this ARCustomer datacontextObject)
{
   var arCustomer = new ArCustomer();
   arCustomer.Id = datacontextObject.ProjectID;
   // more of the same

   // now populate the other fields that don't exist on the datacontextObject

   return arCustomer;
}

then the data access code looks like this

var customerfromDb = accountReceivableRepository.GetCurCustomer(arId);
ArCustomer customer = customerfromDb.ToDomainObject();
绅刃 2024-12-06 16:41:53

几天前我也遇到了同样的问题。我确实找到了一些关于这个主题的讨论。
这些线程可能会有所帮助:线程一, 线程二

据我所知,没有更好的方法了你在做什么。但是,您可能会尝试使用反射来迭代父对象中的所有字段,以将它们复制到子对象中的相关字段。 这里有一些示例代码这里进行讨论

对于我的问题,最终手动逐个字段进行处理,因为我需要深度克隆某些字段,有些字段只能通过引用进行复制。

Few days ago I had the same problem. And I did find some discussions on this topic.
These threads might help: Thread one, Thread two

As I figured out, there is no better way to do what you are doing. However, you might try to use reflection to iterate through all the fields in parent object to copy them to relevant fields in child object. Some example code here, And discussion here.

For my problem, ended up going field by field manually, as some of the fields I needed to be deeply cloned, some had to be copied only by reference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文