2015-03-11 4 views
0

У меня есть несколько объектов в моем решении, которые используют следующую схему:Наследование класса с требуемым конструктором в дженериков

#region Repositories 
private RepositoryAccount _account; 
private RepositoryInquiry _inquiry; 
private RepositoryLoan _loan; 

public RepositoryAccount Account { get { return _account ?? (_account = new RepositoryAccount(this)); } } 
public RepositoryInquiry Inquiry { get { return _inquiry ?? (_inquiry = new RepositoryInquiry(this)); } } 
public RepositoryLoan Loan { get { return _loan ?? (_loan = new RepositoryLoan(this)); } } 
#endregion 

Я создал универсальный класс, чтобы попытаться сделать свойство обработки немного чище, но врезался в корягу , Класс недвижимости выглядит следующим образом:

public class Property<T> where T : class, new() 
{ 
    private T _value; 

    public T Value 
    { 
     get { return _value ?? (_value = new T()); } 
     set 
     { 
      // insert desired logic here 
      _value = value; 
     } 
    } 

    public static implicit operator T(Property<T> value) 
    { 
     return value.Value; 
    } 

    public static implicit operator Property<T>(T value) 
    { 
     return new Property<T> { Value = value }; 
    } 
} 

я заменить мою собственность (с объектами отступающих) с новой Generic собственности как:

public Property<RepositoryAccount> Account { get; set; } 
public Property<RepositoryInquiry> Inquiry { get; set; } 
public Property<RepositoryLoan> Loan { get; set; } 

Однако, если вы заметили, в первоначальном общественном добытчика, мне нужно создавать экземпляр каждого объекта с другим объектом: это требуется, и для этих объектов репозитория не существует конструктора без партера.

Любые предложения?


Весь объект выглядит следующим образом:

public class UnitOfWorkSymitar : IUnitOfWork 
{ 
    #region Properties 
    internal IPHostEntry IpHostInfo; 
    internal IPAddress IpAddress; 
    internal IPEndPoint RemotEndPoint; 
    internal System.Net.Sockets.Socket Sender; 
    internal byte[] Bytes = new byte[1024]; 
    internal bool IsAllowedToRun = false; 
    internal string SymServerIp; 
    internal int SymPort; 
    public string State { get; set; } 
    #endregion 

    #region Constructor 
    public UnitOfWorkSymitar() { OpenSymitarConnection(); } 
    protected UnitOfWorkSymitar(string serverIp, int? port) { OpenSymitarConnection(serverIp, port); } 
    #endregion 

    #region Implement IUnitOfWork 
    public void Commit() { /* No commit on this socket connection */ } 
    public void Rollback() { /* No rollback on this socket connection */ } 
    #endregion 

    #region Implement IDisposable 
    /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary> 
    public void Dispose() 
    { 
     CloseSymitarConnection(); 
    } 
    #endregion 

    #region Private Helpers 
    /// <summary> 
    /// Connect to a remote device. 
    /// </summary> 
    /// <returns>Success/failure message</returns> 
    private string OpenSymitarConnection(string serverIp = null, int? port = null) 
    { 
     var config = ConfigInfoSymitar.Instance; 
     SymServerIp = serverIp ?? config.SymServerIp; 
     SymPort = port ?? config.SymPort; 
     try 
     { 
      // Establish the remote endpoint for the socket. 
      //IpHostInfo = Dns.GetHostEntry(SymServerIp); 
      //IpAddress = IpHostInfo.AddressList[0]; 

      IpAddress = Dns.GetHostAddresses(SymServerIp)[0]; 

      RemotEndPoint = new IPEndPoint(IpAddress, SymPort); 
      // Create a TCP/IP socket. 
      Sender = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

      // Connect the socket to the remote endpoint. Catch any errors. 
      Sender.Connect(RemotEndPoint); 
     } 
     catch (Exception ex) 
     { 
      State = DetermineError(ex); 
      return State; 
      //throw; 
     } 

     IsAllowedToRun = true; 
     State = "Success"; 
     return State; 
    } 
    /// <summary> 
    /// Setup and send the request 
    /// </summary> 
    /// <param name="request"></param> 
    /// <returns></returns> 
    public string SendMessage(string request) 
    { 
     try 
     { 
      // Encode the data string into a byte array and add the carriage return for SymConnect. 
      var msg = Encoding.ASCII.GetBytes(request); 
      if(!request.EndsWith("\n")) 
       msg = Encoding.ASCII.GetBytes(request + "\n"); 
      // Send the data through the socket. 
      var bytesSent = Sender.Send(msg); 
      // Receive the response from the remote device. 
      var bytesRec = Sender.Receive(Bytes); 
      var response = Encoding.ASCII.GetString(Bytes, 0, bytesRec); 
      response = response.Replace("\n", ""); 
      return response; 
     } 
     catch (Exception ex) 
     { 
      return DetermineError(ex); 
     } 
    } 
    /// <summary> 
    /// Close the connection to a remote device. 
    /// </summary> 
    /// <returns></returns> 
    private string CloseSymitarConnection() 
    { 
     try 
     { 
      // Release the socket. 
      Sender.Shutdown(SocketShutdown.Both); 
      Sender.Close(); 
     } 
     catch (Exception ex) 
     { 
      return DetermineError(ex); 
     } 
     finally 
     { 
      IsAllowedToRun = false; 
     } 
     return "Success!"; 
    } 
    /// <summary> 
    /// Determine if this is an Arguments, Socket or some other exception 
    /// </summary> 
    /// <param name="ex">The exception to be checked</param> 
    /// <returns>String message</returns> 
    private static string DetermineError(Exception ex) 
    { 
     if (ex.GetType() == typeof(ArgumentNullException)) 
      return "Missing Arguments: " + Environment.NewLine + ex.GetFullMessage(); 
     if (ex.GetType() == typeof(SocketException)) 
      return "Socket Error: " + Environment.NewLine + ex.GetFullMessage(); 
     return "Unexpected Error: " + Environment.NewLine + ex.GetFullMessage(); 
    } 
    #endregion 

    #region Symitar Samples 
    private static string ExecSymConnectRequest(string symServerIP, int symPort, string request) 
    { 
     // Data buffer for incoming data. 
     var bytes = new byte[1024]; 
     // Connect to a remote device. 
     try 
     { 
      // Establish the remote endpoint for the socket. 
      // This example uses port 11000 on the local computer. 
      var ipHostInfo = Dns.GetHostEntry(symServerIP); 
      var ipAddress = ipHostInfo.AddressList[0]; 
      var remoteEP = new IPEndPoint(ipAddress, symPort); 
      // Create a TCP/IP socket. 
      var sender = new System.Net.Sockets.Socket(AddressFamily.InterNetwork 
            , SocketType.Stream 
            , ProtocolType.Tcp); 

      // Connect the socket to the remote endpoint. Catch any errors. 
      try 
      { 
       sender.Connect(remoteEP); 
       // Encode the data string into a byte array and add the carriage return for SymConnect. 
       var msg = Encoding.ASCII.GetBytes(request + "\n"); 
       // Send the data through the socket. 
       var bytesSent = sender.Send(msg); 
       // Receive the response from the remote device. 
       var bytesRec = sender.Receive(bytes); 
       var response = Encoding.ASCII.GetString(bytes, 0, bytesRec); 
       // Release the socket. 
       sender.Shutdown(SocketShutdown.Both); 
       sender.Close(); 
       response.Replace("\n", ""); 
       return response; 
      } 
      catch (ArgumentNullException ane) 
      { 
       return "Missing Arguments: " + ane.Message; 
      } 
      catch (SocketException se) 
      { 
       return "Socket Error: " + se.Message; 
      } 
      catch (Exception e) 
      { 
       return "Unexpected Error: " + e.Message; 
      } 
     } 
     catch (Exception e) 
     { 
      return e.Message; 
     } 
    } 
    #endregion 

    #region Repositories 
    private RepositoryAccount _account; 
    private RepositoryInquiry _inquiry; 
    private RepositoryLoan _loan; 

    public RepositoryAccount Account { get { return _account ?? (_account = new RepositoryAccount(this)); } } 
    public RepositoryInquiry Inquiry { get { return _inquiry ?? (_inquiry = new RepositoryInquiry(this)); } } 
    public RepositoryLoan Loan { get { return _loan ?? (_loan = new RepositoryLoan(this)); } } 
    #endregion 
} 
+0

У вас есть право собственности на классы хранилища? Не могли бы вы дать им конструктор без параметров и затем добавить другие обязательные атрибуты? –

+0

Только в том случае, если я создаю объект Property, инициализирую его и т. Д. Я не буду сохранять что-либо к моменту окончания. И в Хранилищах используется базовый класс, который применяет параметризованный конструктор. Было бы довольно много усилий переделать весь код уровня доступа к данным. –

ответ

0

Может попробовать что-то вроде:

class Program { 
    Property<string> Foo = new Property<string>(() => "FOO!"); 
} 

public class Property<T> where T : class { 
    private Lazy<T> instance; 

    public Property(Func<T> generator) { 
     instance = new Lazy<T>(generator); 
    } 

    public T Value { 
     get { return instance.Value; } 
    } 

    public static implicit operator T(Property<T> value) { 
     return value.Value; 
    } 

    public static implicit operator Property<T>(T value) { 
     return new Property<T>(() => value); 
    } 
} 
0

Существует решение с помощью отражения, хотя оно не может быть чистым OOP один. Метод класса FormatterService в пространстве имен System.Runtime FormatterServices.GetUninitializedObject() создаст экземпляр без вызова конструктора. Существует аналогичный ответ на эту проблему here.

Чтобы сделать работу с вашим решением, вы должны внести некоторые изменения в свой код. Прежде всего удалите новый() из вашего общего объявления класса Property, иначе вы всегда получите ошибку от компилятора, если попытаетесь использовать тип T без конструктора без параметров. Во-вторых добавить этот метод к вашему Property классу:

private T GetInstance() 
{ 
    return (T)FormatterServices.GetUninitializedObject(typeof(T)); //does not call ctor 
} 

Он возвращает объект инициализирован, но это не будет вызывать конструктор.

Вот полный код:

public class Property<T> where T : class 
{ 
    private T _value; 

    public T Value 
    { 
     get 
     { 
      return _value ?? (_value = GetInstance()); 
     } 
     set 
     { 
      // insert desired logic here 
      _value = value; 
     } 
    } 

    private T GetInstance() 
    { 
     return (T)FormatterServices.GetUninitializedObject(typeof(T)); //does not call ctor 
    } 

    public static implicit operator T(Property<T> value) 
    { 
     return value.Value; 
    } 

    public static implicit operator Property<T>(T value) 
    { 
     return new Property<T> { Value = value }; 
    } 
} 

Я создал gist here, вы можете попробовать код в LINQPad и увидеть результат.

надеюсь, что это поможет.