Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Generic Interface with different return types

I have webservice that can return data in multiple formats. For example json and xml. I'm building a simple C# api against this webservice and I would like the methods to be able to return either fully serialized objects from json, raw json or raw xml. For example:

List<Order> GetOrders(int customerId)
string GetOrders(int customerId)
XMLDocument GetOrders(customerId)

Customer GetCustomer(int customerId)
string GetCustomer(int customerId)
XMLDocument GetCustomer(int customerId)

I have an idea about doing a fluent api where you would call a SetFormat() method which would then return a common Interface for the above methods. But I'm stuck on how that interface would look like, since the implementation that returns serialized objects returns objects of different types.

Another simpler solution would to just have the methods that return serialized objects and then add an out paramater like this:

List<Order> GetOrders(int customerId, out string data)

but that's not very nice solution I think....

UPDATE

I prefered the none-generic solution that Sjoerd suggested, I had over-complicated my problem. This is what I ended up doing:

public class ServiceEntity {
    List<Order> GetOrders(int customerId)....
}    
public class ServiceJson {
    string GetOrders(int customerId)....
}
public class ServiceXml {
    XmlDocument GetOrders(int customerId)....
}

Then a fluent service class like this:

public class Service : IService {
    ....
    public AsJson() { return new ServiceJson(); }
    public AsEntity() { return new ServiceEntity(); }
    public AsXml() { return new ServiceXml(); }
}

Used like this:

string json = Service.New().AsJson().GetCategories(1);
List<Order> = Service.New().AsEntity().GetCategories(1);

Thanks for all the replies!

like image 762
ZNS Avatar asked Oct 20 '11 13:10

ZNS


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr. Stroustroupe.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


2 Answers

It's nice to try to use generics, but generics are not a silver bullet!

In this case, I wonder how much code would you save compared with the non-generic:

List<Order> GetOrdersAsList(int customerId)
string GetOrdersAsString(int customerId)
XMLDocument GetOrdersAsXml(customerId)

I bet almost none!

And in case you decide on the non-generic approach, most likely it would end up internally as:

List<Order> GetOrders(int customerId)
string OrdersToString(List<Order> orders)
XMLDocument OrdersToXml(List<Order> orders)

Then the latter two methods could be moved to separate classes, resulting in the fact that your GetOrders() is uncoupled from the format.

That seems to me a much better and cleaner approach than trying to use generics in this case!

UPDATE: Don't get me wrong, I like generics and in many cases they make code more readable. Several other answers are very interesting as they show techniques to achieve that. So I recommend to study them: they might be useful in other cases. But in this case, each proposed solution so far has a practical drawback. That's why I recommend non-generics in this case.

like image 158
Sjoerd Avatar answered Oct 24 '22 16:10

Sjoerd


You could also have a look at using an implicit operator to return the data as expected.

For example the following class:

public class OrderThingy 
{
    public static implicit operator List<Order>(OrderThingy orderthingy)
    {
        // Use CustomerId to get the data
        return new List<Order>();
    }

    public static implicit operator string(OrderThingy orderthingy)
    {
        // Use CustomerId to get the data
        return "string representation";
    }

    public static implicit operator XDocument(OrderThingy orderthingy)
    {
        // Use CustomerId to get the data
        return new XDocument();
    }

    private int CustomerId { get; set; }

    public OrderThingy GetOrders(int customerId)
    {
        CustomerId = customerId;
        return this;
    }
}

And you could use it like this:

XDocument doc = new OrderThingy().GetOrders(1);
List<Order> orders = new OrderThingy().GetOrders(2);
string stringorders = new OrderThingy().GetOrders(2);
like image 31
Wouter de Kort Avatar answered Oct 24 '22 16:10

Wouter de Kort