I'm writing a library in C# that is meant to abstract calls from a third-party API, such that it can accept inputs from multiple potential applications. Currently, I have three broad classes:

  • Base class: authentication, request formatting, foundational data retrieval for any API requests
  • Reader class: data retrieval that is NOT foundational - "nice to haves", or important abstractions outside of object creation
  • Writer class: any sort of a "push" to the API, i.e. updating information on their side in some way - many of these calls return important values in addition to the expected "pass/fail" information

The API itself is RESTful, and as such has no explicit differentiation between reads and writes - rather it just denotes which HTTP verb a request uses. I broke my design up into base/reader/writer as it made it clearer for me which abstractions did what, as they extend what is defined in the API.

Now, I have an issue. The data defined in the base class can typically be considered "session-level". There are situations where it would be very helpful to share it between the reader and writer. Currently I have an ugly-looking "memberwise clone" to do this. I didn't use the built-in as there are certain properties that I am intentionally omitting.

Is there a better way to do this? Any other criticisms of my design are certainly welcome as well - I am getting some code smells here.



To answer John - in many situations I need to copy more than 3-4 values so that reads and writes can be routed to the same place, as they are both occurring in the same "session". The Base class holds a pool of properties to properly store any incoming values - typically some, but not all, are used. That is why I called my "cloning" ugly.

A simple reason I made the clone was that I have a Base constructor that generates a token for API requests, and also instantiates a class-level HttpClient. If I create a Writer from a Reader, I don't want to recreate the token and HttpClient - I want to use what is already there, so I created a new constructor for that purpose.

Regarding your comment on inheritance Flater, I would agree - I just wanted to ensure the derived classes had certain methods and properties. Since I needed both, an interface wasn't an option. The issue could be summarized as poor design and the need for the aforementioned cloning method - in the end, it may be better to eschew it and just copy on the fly as John suggested. I just want to avoid a Reader needing a Writer instance for that and vice-versa.

I'll see what I can do about posting code, but the API is a paid product, and my code is pretty closely abstracted around their conventions. If you have ideas on how I can post a concrete example with those restrictions, I'm all ears.

New contributor
Antidiscrete is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • 1
    I don't understand. If the common code is in the base class, it is accessible to the descendent classes, e.g. using protected members. What do you need the ugly-looking memberwise clone for?
    – John Wu
    2 days ago
  • 1
    Your description is unclear, as John Wu indicates. Show us details, show us some code.
    – J_H
    2 days ago
  • 1
    This question seems to be about a very simple form of inheritance design (and potential abuse), pretty much unrelated to the entire API part of the explanation that this question focuses on. It would help to showcase the issue here with a concrete example without sidetracking into explaining how some random third party API is structured.
    – Flater
    2 days ago
  • 1
    Before I see the concrete example, I'm going to make an educated guess here and infer that you're confusing class inheritance with two instances having a shared dependency. Just because Foo and Bar derive from the same Base class does not mean that an instance of Foo and an instance of Bar somehow share the same Base values. Different instances have their own encapsulation.
    – Flater
    2 days ago


Your Answer

Antidiscrete is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.