3

Consider a class with a number of methods that are required to return a number of values each. In a strongly typed language such as C#, we can have the effect of returning more that one value from a method by using DTO classes.

Consider that the values that my methods are to return collectively are these (let's call it the pool):

A, B, C, D, E

But not all methods are required to return all of them. For example, consider the following:

Method      Values to return:
==============================
Method1     A, B, C
Method2     A, E
Method3     B, D, E
Method4     D, E
Method5     A, C, D, E

You get the idea, the values to be returned are assortment of values from the pool.

This code should help it make the situation clearer. I am using C# here.

namespace TestBed
{
    public interface MyInterface
    {
        MyDTO Method1(/* parameters */);
        MyDTO Method2(/* parameters */);
        // definitions for Method3() and so on
    }

    // Writing the DTO class here, as it is specific only to the class
    // that implements this interface
    public class MyDTO
    {
        public string A { get; set; }
        public string B { get; set; }
        public string C { get; set; }
        public string D { get; set; }
        public string E { get; set; }

        // possibly a constructor
    }
}

A class implementing the interface:

public class MyClass : MyInterface
{
    public MyDTO Method1(/* parameters */)
    {
        MyDTO dto = new MyDTO();
        // populate the properties of dto specific to this method
        dto.A = "some values for A";
        dto.B = "some values for B";
        dto.C = "some values for C";

        return dto;
    }

    public MyDTO Method2(/* parameters */)
    {
        MyDTO dto = new MyDTO();
        // populate the properties of dto specific to this method
        dto.A = "some values for A";
        dto.E = "some values for E";

        return dto;
    }

    // similar code for the other methods
}

As you can see, a method say Method1() populates only the properties of the dto that are relevant to it, e.g. A, B and C for Method1(). My concerns are:

  • Although a method populates only the properties relevant to it, the callee of this method can access other values of the DTO too, e.g. the properties D and E for the Method1().
  • A method which populates only few number of values of the DTO (only 2 for Method4()), still returns an object with a lot of other values that are not useful for this method. It looks like an unnecessary overhead.

Regarding the concerns above, why (or why not, perhaps) should I use a DTO in such cases? Is there any better alternative approach in this scenario, at least until C# 7 is around.

  • Why not use a different DTO for each method? – jhyot Oct 16 '16 at 17:36
  • @jhyot Yes, of course that's an option, but what if the number of such values is more than just 5 as in the example, rather it is say 10, and hence number of assortment is also too great, say for 20 functions 15 different combinations of the values. Do you think it is still good to write 15 different DTOs? – Sнаđошƒаӽ Oct 16 '16 at 17:53
  • Maybe it becomes too cumbersome at some point... but on the other hand, if you have so many return types, that's just what you have. Maybe you should look closer at your domain model to see if you can refactor classes and methods so as to reduce the many combinations. – jhyot Oct 17 '16 at 6:03
1

Return a collection of KeyValuePair<K,V> with only the values for the particular method called.

OR

Return a particular Tuple type for a given MethodX.

OR

Default the values you are not sending. This could be a problem: how do you tell the difference between "ignore me" vs its value IS that default.

OR

parameterize the method to tell what values are desired. The return type/structure is up to you.

OR

Give the client the burden of ignoring the right stuff. In which case I can see a proliferation of more anemic "DTO" classes on the client side.

Give the client something they can actually work with

Whatever the implementation, it should be in the DTO class itself. Thus the DTO is no longer a DTO per se, but a "real" class as it should be. As a bonus you can forget all that interface overhead.

  • I like the key-value pair idea, although I would like to have something more static. Tuple seems very clumsy, since I would have to know which ItemX contains which value. – Sнаđошƒаӽ Oct 17 '16 at 5:33
1

I am not sure how much sense that'll make, but, FWIW:

(contrived)

/// <summary>
/// TDto below not meant to be closed over the actual DTOs, but only
/// local proxies of those that a (likewise) proxy implementation of
/// the interface will reflect over/interpret (cf. System.Reflection)
/// before forwarding the call to the actual service client,
/// with the actual DTOs
/// </summary>
public interface IMyBusinessFacade
{
    TDto GetById<TDto, TIdentifier>(TDto protoDto, TIdentifier id)
        // DTOs being anemic by their very nature, whatever will be TDto on call sites (as a closed type)
        // we can reasonably expect it to come as either (a) a named reference type
        // (most likely with a public parameter-less constructor) or
        // (b) an anonymous type that a proxy can validate (or not) before even bothering
        // to forwarding to the service layer
        where TDto : class;

    IEnumerable<TDto> GetFiltered<TDto, TCriteria>(TDto protoDto, TCriteria criteria)
        where TDto : class;
}

// If the tooling can generate service clients, it might as well generate
// such local proxies for those clients
public class MyBusinessFacade : /*ProxyBase, */IMyBusinessFacade
{
    private IMyBusinessService service;

    public MyBusinessFacade(IMyBusinessService service)
    {
        this.service = service;
    }

    public TDto GetById<TDto, TIdentifier>(TDto protoDto, TIdentifier id)
        where TDto : class
    {
        // auto-generated implementation to use reflection over typeof(TDto)
        // and typeof(TIdentifier) before forwarding the calls to the service layer
        // if applicable (or throw exception on invalid client-specified input)
        // ...
        // resolve, using this.service
        // ...
        // instantiate and hydrate a TDto, if applicable
        TDto dto = ...
        // and return it
        return dto;
    }

    public IEnumerable<TDto> GetFiltered<TDto, TCriteria>(TDto protoDto, TCriteria criteria)
         where TDto : class
    {
        // ...
        // resolve, using this.service
        // ...
        // instantiate and hydrate an IEnumerable<TDto>, if applicable
        IEnumerable<TDto> dtos = ...
        // and return it
        return dtos;
    }
}

public enum CustomerKind
{
    Regular,
    Premium
}

public enum SubscriptionType
{
    OneMonthTrial,
    MonthlyAutoRenew
}

Then, later on:

        // (actual service client)
        IMyBusinessService myService = ...
        // ...
        IMyBusinessFacade myFacade = new MyBusinessFacade(myService);

        var GetCustomerById =
            new
            {
                // the facade/proxy will relate/interpret this property's
                // type & name (but not its useless value) with that of the id parameter
                CustomerId = default(int),

                // facade/proxy to interpret those too, as what the caller
                // expects:
                CustomerKind = default(CustomerKind),
                // etc
            };

        var GetCustomerContractById =
            new
            {
                ContractId = default(int),

                // facade/proxy to interpret those too, as what the caller
                // expects:
                Customer = GetCustomerById,
                SubscriptionType = default(SubscriptionType),
                // etc
            };

        var customer123 = myFacade.
            GetById
            (
                GetCustomerById,
                123
            );

        var contrat456 = myFacade.
            GetById
            (
                GetCustomerContractById,
                456
            );

        Console.WriteLine("Customer: {0}, {1} ...", customer123.CustomerId, customer123.CustomerKind);
        Console.WriteLine("Contract: {0} (Customer: {1}) Subscription: {2} ...", contrat456.ContractId, contract456.Customer.CustomerId, contract456.SubscriptionType);

Granted, a rather hacker-ish use of C#'s type inference combined with anonymous types, albeit nothing new, really, as that's what, for instance, some JSON serializers already do, for the caller's convenience, as with, e.g.:

JSON.NET's Deserialize an Anonymous Type

'Hope this helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.