【问题标题】:C# - Constructor with generic parameters transmitting these parameters to base constructorC# - 具有泛型参数的构造函数将这些参数传输到基本构造函数
【发布时间】:2023-03-07 04:45:01
【问题描述】:

在这个网站上,有很多问题在逼近我,虽然不同,但我找不到答案。 我为泛型类带来的多态性限制而苦恼。

  1. CW1消息:

     public abstract class CW1Message {
         private CW1Connection _ConnectionConfig;
    
         protected CW1Message(CW1Connection conn) {
             ConnectionConfig = conn;
         }
    
         protected internal CW1Connection ConnectionConfig { get => _ConnectionConfig; set => _ConnectionConfig = value; }
     }
    
  2. CW1Request 和 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 和 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 和 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
         }
     }
    

问题在于代码 sn-p:

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

Argument1:无法从“UniversalRequest”转换为“CW1Request”。

UniversalRequest 继承自 CW1Request,UniversalResponse 继承自 CW1Response。我想编译器不喜欢添加更严格的约束,但我不知道如何正确编写。

【问题讨论】:

    标签: c# generics inheritance polymorphism


    【解决方案1】:

    问题在于使用泛型类型时继承是如何工作的。

    B_Response inherits from A_Response
    
    B_Request<T> inherits from A_Request<T>
    

    即使 T1 继承自 T2

    B_Request<T1> NEVER INHERITS FROM B_Request<T2>
    

    这意味着 B_Request 不继承自 A_Request 并且如果以这种方式设计,您将无法使用 A_Response 的基本构造函数。 这与将 List 传递给以 List 作为输入的方法相同。此方法可以将对象添加到字符串列表中,这是不正确的。

    基于 A_Request、B_Request、A_Response 和 B_Response 之间的差异,可以有很多选择。 如果您可以分享您的代码,我们可以一起找到解决方案。

    如果您只想编译,只需将构造函数留空即可。

    【讨论】:

    • 谢谢。除了对研究此案例无用的所有方法外,我添加了更多细节。那么如何将参数传递给我的基类的构造函数?
    • 如果 B_Response 没有添加任何方法或将任何逻辑更改为 A_Response,请不要使用 B_Response 并始终使用 A_Response
    • A_Response 的后代使用不同的逻辑解析响应 XML 字符串参数。响应构建在相应请求的 Send() 方法中。我认为我能做的最好的事情就是修改响应构造函数以始终使用 A_Request 并使其成为内部(因为响应始终由请求构建)。我用请求调用响应构造函数,以便同时传输所有上下文信息,但我认为我可以使用覆盖方法或属性并依赖多态性。
    • 哦...我不能这样做,因为我的构造函数也不需要我的参数...我只是在解决问题...
    • 能否将“Send”方法的详细信息添加到 sn-p 中?
    猜你喜欢
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 2014-12-25
    • 2019-01-06
    • 1970-01-01
    • 1970-01-01
    • 2018-04-08
    • 2011-10-08
    相关资源
    最近更新 更多