简体   繁体   中英

How to return generic object that could be from two different types

I'm trying to create a middle layer that will allow me a to connect to either a Live service or a Test service without making changes to my client.

I need to return a generic object called Product to use in the client. I get this from the middle layer but I don't need to know how I get this or where it's from. The middle layer connects to a live and test service and I just call a method to get the stuff I need.

The problem is returning the product I got from whichever service back to the client. The method is expecting Product but it's trying to send LiveService.Product or TestService.Product .

Is there any way to convert these types into a generic Product type so they can be returned to the client?

Below is what I have created so far.

Client

Connection conn = new Connection("Test");
IServiceImplementation service = conn.GetServiceImplementation();
Product prod = service.GetProductUsingId(123);

Middle Layer

public interface IServiceImplementation
{
    Product GetProductUsingId (int productID);
}

public class Connection
{
    private string mode;

    public Connection(string _Mode)
    {
        mode = _Mode;
    }

    public IServiceImplementation GetServiceImplementation()
    {
        if (mode == "Live")
        {
            return new LiveService();
        }
        else if (mode == "Test")
        {
            return new TestService();
        }
        else
        {
            return null;
        }
    }
}

Public class LiveService : IServiceImplementation
{
    public Product GetProductUsingId (int productID)
    {
        LiveService.Service live = new LiveService.Service();
        return live.GetProduct(2638975);
    }
}

Public class TestService : IServiceImplementation
{
    public Product GetProductUsingId (int productID)
    {
        TestService.Service test = new TestService.Service();
        return test.GetProduct(2638975);
    }
}

The easiest answer is to define your own Product class to return.

public class MyProduct
{
    //some properties 
}

public MyProduct GetProductUsingId (int productID)
{
    LiveService.Service live = new LiveService.Service();
    var product = live.GetProduct(2638975);
    var myProduct = new MyProduct();

    //Copy properties 
    myProduct.SomeProp = product.SomeProp;
    //etc

    return myProduct;
}

The alternative is to use partial classes. The Product class in each service namespace should already be defined as partial . Create another part of the partial in another file for each service type and inherit an interface:

namespace SomeSharedNamespace
{
    public interface IProduct
    {
        //shared properties you need
    }
}

namespace LiveService
{
    public partial class Product : IProduct
    {
        //implement interface
    }
}

namespace TestService
{
    public partial class Product : IProduct
    {
        //implement interface
    }
}

Now each Product implements the IProduct interface, so return that

public IProduct GetProductUsingId (int productID)
{
    LiveService.Service live = new LiveService.Service();
    return live.GetProduct(2638975);
}

As you have seen, Product, LiveService.Product, and TestService.Product are three different types and cannot be converted to each other.

If you cannot arrange for the same type to be used, or for LiveService.Product and TestService.Product to inherit from Product, then your next option is to copy the properties from Live(Test)Service.Product to Product.

In my example, I used AutoMapper to copy the property values from the Live(Test)Service.Product to Product.

It is worth mentioning that these are three different types and if any properties of the any of the three types are changed, that could cause problems. With AutoMapper, any property names that don't match will fail to copy, without displaying any error. That could cause you to overlook the fact that a property value is not being passed.

public IServiceImplementation GetServiceImplementation()
{
    if (mode == "Live")
    {
        return new LiveServiceImplementation();
    }
    else if (mode == "Test")
    {
        return new TestServiceImplementation();
    }
    else
    {
        return null;
    }
}

public class LiveServiceImplementation : IServiceImplementation
{
    public LiveServiceImplementation()
    {
        Mapper.CreateMap<LiveService.Product, Product>();
    }

    public Product GetProductUsingId(int productID)
    {
        LiveService.Service _service = new LiveService.Service();
        return Mapper.Map<LiveService.Product, Product>(_service.GetProduct(2638975));
    }
}

public class TestServiceImplementation : IServiceImplementation
{
    public TestServiceImplementation()
    {
        Mapper.CreateMap<TestService.Product, Product>();
    }

    public Product GetProductUsingId(int productID)
    {
        TestService.Service _service = new TestService.Service();
        return Mapper.Map<TestService.Product, Product>(_service.GetProduct(2638975));
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM