Reorganize classes structure

2019-07-22 15:00发布

Referencing to my previous question, the story begins in that fact that I have a bunch of svcutil-generated classes. They are generated from external WSDL. Here you go:

First request class:

public partial class getcarsRequest
{

    [System.ServiceModel.MessageHeaderAttribute(Namespace = "http://svc.datadomains.com/revision123_2/")]
    public CarsServiceApp.RequestHeader Header;

    [System.ServiceModel.MessageBodyMemberAttribute(Name = "getcarsRequest", Namespace = "carinfo", Order = 0)]
    public CarsServiceApp.getcars MessageWrap;

    public getcarsRequest()
    {
    }

    public getcarsRequest(CarsServiceApp.RequestHeader Header, CarsServiceApp.getcars getcarsRequest1)
    {
        this.Header = Header;
        this.MessageWrap = getcarsRequest1;
    }
}

public partial class getcars
{

    private MessageType messageField;

    private MessageDataGetcarsRequest messageDataField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 0)]
    public MessageType Message
    {
        get
        {
            return this.messageField;
        }
        set
        {
            this.messageField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 1)]
    public MessageDataGetcarsRequest MessageData
    {
        get
        {
            return this.messageDataField;
        }
        set
        {
            this.messageDataField = value;
        }
    }
}

public partial class MessageDataGetcarsRequest
{

    private AppDataGetcarsRequest appDataField;

    private AppDocumentType appDocumentField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 0)]
    public AppDataGetcarsRequest AppData
    {
        get
        {
            return this.appDataField;
        }
        set
        {
            this.appDataField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 1)]
    public AppDocumentType AppDocument
    {
        get
        {
            return this.appDocumentField;
        }
        set
        {
            this.appDocumentField = value;
        }
    }
}

public partial class AppDataGetcarsRequest
{
    private string addressField;

    private int codeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 0)]
    public address address
    {
        get
        {
            return this.addressField;
        }
        set
        {
            this.addressField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 1)]
    public int code
    {
        get
        {
            return this.codeField;
        }
        set
        {
            this.codeField = value;
        }
    }

}

Second:

public partial class getdriversRequest
{

    [System.ServiceModel.MessageHeaderAttribute(Namespace = "http://svc.datadomains.com/revision123_2/")]
    public carsServiceApp.RequestHeader Header;

    [System.ServiceModel.MessageBodyMemberAttribute(Name = "getdriversRequest", Namespace = "driverinfo", Order = 0)]
    public carsServiceApp.getdrivers MessageWrap;

    public getdriversRequest()
    {
    }

    public getdriversRequest(carsServiceApp.RequestHeader Header, carsServiceApp.getdrivers getdriversRequest1)
    {
        this.Header = Header;
        this.MessageWrap = getdriversRequest1;
    }
}

public partial class getdrivers
{

    private MessageType messageField;

    private MessageDataGetdriversRequest messageDataField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 0)]
    public MessageType Message
    {
        get
        {
            return this.messageField;
        }
        set
        {
            this.messageField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 1)]
    public MessageDataGetdriversRequest MessageData
    {
        get
        {
            return this.messageDataField;
        }
        set
        {
            this.messageDataField = value;
        }
    }
}

public partial class MessageDataGetdriversRequest
{

    private AppDataGetdriversRequest appDataField;

    private AppDocumentType appDocumentField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 0)]
    public AppDataGetdriversRequest AppData
    {
        get
        {
            return this.appDataField;
        }
        set
        {
            this.appDataField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 1)]
    public AppDocumentType AppDocument
    {
        get
        {
            return this.appDocumentField;
        }
        set
        {
            this.appDocumentField = value;
        }
    }
}

public partial class AppDataGetdriversRequest
{
    private string nameField;

    private int customerCodeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 0)]
    public name name
    {
        get
        {
            return this.nameField;
        }
        set
        {
            this.nameField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 1)]
    public int customerCode
    {
        get
        {
            return this.customerCodeField;
        }
        set
        {
            this.customerCodeField = value;
        }
    }

}

This is just two entity generated by svcutil. There are another entities that like this two differs only by most underlying AppData property. I wrote a power shell script that preparing raw generated file renaming some fields but this is not enough to get all work done.

How can I compose classes unity? It seems like I should use parametrized interface... I need united classes structure to devise common useful functions like checking that request is correct or create request from scratch.

Thanks in advance, guys! My brains are boiled about that stuff.


QUESTION EDIT #1

Ok, guys, here is that I would like to have. Let say we want to check any service method's request for correctness. If some request's AppData property isn't null we should consider that request as correct. Actually it would be better for us to have some common class' method for such checking. But how can we make that method if any request class has different AppData property types?

Let take a look at two generated classes and draw some imaginary path to each AppData properties.

For first class, getcarsRequest we have (in parentheses we has appropriate class type):

request (getcarsRequest) -> MessageWrap (getcars) -> MessageData (MessageDataGetcarsRequest) -> AppData (AppDataGetcarsRequest)

For the second we have next path:

request (getdriversRequest) -> MessageWrap (getdrivers) -> MessageData (MessageDataGetdriversRequest) -> AppData (AppDataGetdriversRequest)

So how can we redevise and reduce them to some generic interface? If we have an appropriate, common interface for that two classes we could write some CheckRequest(IRequest<T> request).

I hope I get some clarity here. Any advices/sentences will be very appreciated. If you have any questions for me please feel free to bring them to me.

3条回答
疯言疯语
2楼-- · 2019-07-22 15:34

As I understand it, you have two class structures that are effectively duplicated: car and driver. Instead of modifying the generated classes, you should focus on restructuring your input wsdl (which we havent seen yet).

In order to remove this duplication, consider making two Objects: car and driver and restructuring the wsdl operations in such a way that they can operate on either type of Object. In Object Oriented terms, both car and driver should inherit from the same base class that will have abstract methods that can be called by the wsdl operations. These abstract methods would then need to be implemented in the car and driver derived/concrete classes.

查看更多
趁早两清
3楼-- · 2019-07-22 15:46

Refactoring might be the best option, but if it isn't feasible, you can take advantage of the fact that they're partial and add an interface.

public IData<TRequest>  {
    T AppData { get; set; }
    bool IsValid { get; }
}
public partial class MessageDataGetdriversRequest : IData<AppDataGetcarsRequest>
{
    bool IsValid { get { this.AppData != null; } }
}
public partial class MessageDataGetdriversRequest: IData<AppDataGetdriversRequest>
{
    bool IsValid { get { this.AppData != null; } }
}

Then you can do var data = getcars.MessageData; or var data = getdrivers.MessageData;, and then check data.IsValid.

It's also possible to implement IsValid as an extension method on this IData<T> instead of a property of IData, in which case you wouldn't even need to declare it for each class (but it would be a method, not a property).

public partial class MessageDataGetdriversRequest : IData<AppDataGetcarsRequest> { }
public partial class MessageDataGetdriversRequest: IData<AppDataGetdriversRequest> { }

public static bool IsValid(this IData<T> data)
{
    return data.AppData != null;
}
查看更多
ら.Afraid
4楼-- · 2019-07-22 15:54

If you cannot edit your WSDL to provide a common type, I see two possibilities:

  1. You could create generic wrapper classes that are parametrized with the known type. The classes would mimic the structure of the concrete classes (generated by svcutil) including their hierarchy. Then you wrap the raw object in the appropritate wrapper and use the wrapper from that point on.

    Advantage: interaction with the wrapper classes are similar to the original (raw) objects without much runtime overhead.

    Disadvantage: You need to create and maintain the class layout/hierarchy of the original (raw) objects as the WSDL changes.

  2. Alternatively, you can use reflection to call the appropriate methods on the objects -- you will need to calculate the method names based on the concrete type (e.g. callFunction(o, "get", "car") to call ((GetCarsRequest)o).getCars()).

    Advantage: you do not need to create and maintain a shadow type hierarchy to match the original type layout/hierarchy.

    Disadvantage: reflection in general is much slower than achieving the same result via compiled bytecode.

Both of these approaches require you to know for sure at all times which type of object you are dealing with, which should not be an issue as that is the case already in your current setup.

查看更多
登录 后发表回答