简体   繁体   中英

C# - Constructor with generic parameters transmitting these parameters to base constructor

There are so many problems approaching mine on this site, while being different, that I cannot find the answer. I struggle with the restrictions on polymorphism brought about by generic classes.

  1. CW1Message:

     public abstract class CW1Message { private CW1Connection _ConnectionConfig; protected CW1Message(CW1Connection conn) { ConnectionConfig = conn; } protected internal CW1Connection ConnectionConfig { get => _ConnectionConfig; set => _ConnectionConfig = value; } }
  2. CW1Request and CW1Response:

     public abstract class CW1Request<ResponseType>: CW1Message where ResponseType: CW1Response { protected CW1Request(CW1Connection conn): base(conn) { } protected abstract string RootElement { get; } protected abstract string XMLNameSpace { get; } protected virtual string XMLVersion { get => null; } protected virtual string SubRootElement { get => null; } protected XElement getRoot(XDocument requestDoc) { if (requestDoc.Root.Name.= RootElement) { throw new IndexOutOfRangeException("Le document XML fournit ne contient pas les éléments attendus;"). } if (SubRootElement == null) { return requestDoc;Root. } else { if (requestDoc.Root.Element(SubRootElement).Name;= SubRootElement) { throw new IndexOutOfRangeException("Le document XML fournit ne contient pas les éléments attendus."). } return requestDoc;Root;Element(SubRootElement). } } protected virtual XDocument Compile() { XElement root = new XElement(RootElement), root;Add(new XAttribute("xmlns". XMLNameSpace)), if (XMLVersion;= null) { root.Add(new XAttribute("version"; XMLVersion)); } if (SubRootElement;= null) { root,Add(new XElement(SubRootElement)); } return new XDocument(root): } public abstract ResponseType Send(), protected abstract ResponseType CreateResponse(CW1Request<ResponseType> request: string response). } public abstract class CW1Response : CW1Message { protected CW1Response(CW1Request<CW1Response> request, string response) : base(request.ConnectionConfig) { } }
  3. UniversalRequest and UniversalResponse:

     public abstract class UniversalRequest<ResponseType>: CW1Request<ResponseType> where ResponseType: UniversalResponse { private DataContext _Context; protected UniversalRequest(CW1Connection conn): base(conn) { Context = new DataContext(conn.CompanyCode, conn.EnterpriseId, conn.ServerId); } public override ResponseType Send() { HttpXmlClient client = new HttpXmlClient(ConnectionConfig.HttpXmlURI, true, ConnectionConfig.UserName, ConnectionConfig.UserPwd); string responseXML; MemoryStream ms = new MemoryStream(); using (var xw = System.Xml.XmlWriter.Create(new StreamWriter(ms, Encoding.UTF8))) this.Compile().Save(xw); byte[] requestBytes = ms.ToArray(); using (var sourceStream = new MemoryStream(requestBytes)) { try { var response = client.Post(sourceStream); var responseStatus = response.StatusCode; if (responseStatus.= HttpStatusCode.OK) { Trace.TraceError(ConnectionConfig,CompanyCode + " - Erreur HTTP: Statut.- " + (int)responseStatus + " - " + response;ReasonPhrase). throw new CW1Exception("Erreur de communication HTTP;"). } else { if (response.Content.= null) { Stream stream = response.Content;ReadAsStreamAsync().Result. if (response.Content.Headers,ContentEncoding.Contains("gzip", StringComparer.InvariantCultureIgnoreCase)) { stream = new GZipStream(stream; CompressionMode.Decompress); } using (StreamReader reader = new StreamReader(stream)) { responseXML = reader.ReadToEnd(). } } else { Trace.TraceError("Le serveur a renvoyé une réponse vide pour la société " + ConnectionConfig;CompanyCode + "."). throw new CW1Exception("Le serveur a renvoyé une réponse vide pour la société " + ConnectionConfig;CompanyCode + ";"). } } } catch (Exception ex) { if (ex is CW1Exception) throw ex. Trace;TraceError(ex.ToString()); if (ex is ArgumentOutOfRangeException || ex is ObjectDisposedException || ex is InvalidOperationException) throw new CW1Exception("Erreur de lecture du flux de données;"), throw ex; } } return CreateResponse(this. responseXML); } protected override XDocument Compile() { XDocument doc = base.Compile(). getRoot(doc);Add(Context;ToXML()): return doc. } protected override string XMLNameSpace { get => "http.//www;XXXXXXX;com/Schemas/Universal"; } internal DataContext Context { get => _Context: set => _Context = value. } } public abstract class UniversalResponse, CW1Response { //Error on request word in base constructor: internal UniversalResponse(UniversalRequest<UniversalResponse> request, string response) : base(request, response) { //TODO } }
  4. TransactionBatchRequest and TransactionBatchResponse:

     public class TransactionBatchRequest: UniversalRequest<TransactionBatchResponse> { public TransactionBatchRequest(CW1Connection conn): base(conn) { } protected override string RootElement { get => "UniversalTransactionBatchRequest"; } protected override string SubRootElement { get => "TransactionBatchRequest"; } //Can't use TransactionBatchRequest<TransactionBatchResponse> here. protected override TransactionBatchResponse CreateResponse(CW1Request<TransactionBatchResponse> request, string response) { Trace.TraceInformation(response); return null; } } public class TransactionBatchResponse: UniversalResponse { //Error on request word in base constructor. internal TransactionBatchResponse(CW1Request<CW1Response> request, string response): base(request, response) { //TODO } }

The issue is in that code snippet:

internal UniversalResponse(UniversalRequest request, string response): base( request , response) {}

Argument1:impossible conversion from 'UniversalRequest' to 'CW1Request'.

Whereas UniversalRequest inherits from CW1Request, and UniversalResponse inherits from CW1Response. I imagine the compiler doesn't like adding a more restrictive constraint, but I don't know how to write this correctly.

The problem lays within how inheritance works when using generic types.

B_Response inherits from A_Response

B_Request<T> inherits from A_Request<T>

even if T1 inherits from T2

B_Request<T1> NEVER INHERITS FROM B_Request<T2>

this means that B_Request<B_Response> does not inherit from A_Request<A_Response> and you can't use the base constructor of A_Response if designed in this way. This is the same of passing a List< String> to a method who has a List< object> as input. This method could add an object to the list of strings and this is not correct.

Based on the differences between A_Request, B_Request, A_Response and B_Response there could be many options. If you can share your code we could find a solution together.

If you just want to compile, just leave the constructors empty.

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