在泛型中使用必需的构造函数继承 class
Inheriting class with required constructor in generics
我的解决方案中有几个对象使用以下模式:
#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
我创建了一个通用 Class 来尝试使 属性 处理更干净一些,但 运行 遇到了麻烦。 属性 Class 看起来像:
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 };
}
}
我用新的通用 属性 替换了我的 属性(带有支持对象),例如:
public Property<RepositoryAccount> Account { get; set; }
public Property<RepositoryInquiry> Inquiry { get; set; }
public Property<RepositoryLoan> Loan { get; set; }
但是,如果您在原文中注意到 public getter,我需要用另一个对象实例化每个对象:这是必需的,并且这些存储库对象没有无参数构造函数。
有什么建议吗?
整个对象看起来像:
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
}
有一种使用反射的解决方案,尽管它可能不是最干净的 OOP 解决方案。 System.Runtime 命名空间 FormatterServices.GetUninitializedObject() will create an instance without calling the constructor. There is a similar answer to this problem here.
中 FormatterService class 的方法
为了使其适用于您的解决方案,您必须对代码进行一些更改。首先从你的泛型 class Property
声明中删除 new() 否则如果你尝试使用没有无参数构造函数的类型 T ,你总是会从编译器中得到一个错误。其次将此方法添加到您的 Property
class:
private T GetInstance()
{
return (T)FormatterServices.GetUninitializedObject(typeof(T)); //does not call ctor
}
它将return一个单元化的对象,但不会调用构造函数。
完整代码如下:
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中看看结果。
希望对您有所帮助。
可能会尝试类似的方法:
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);
}
}
我的解决方案中有几个对象使用以下模式:
#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
我创建了一个通用 Class 来尝试使 属性 处理更干净一些,但 运行 遇到了麻烦。 属性 Class 看起来像:
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 };
}
}
我用新的通用 属性 替换了我的 属性(带有支持对象),例如:
public Property<RepositoryAccount> Account { get; set; }
public Property<RepositoryInquiry> Inquiry { get; set; }
public Property<RepositoryLoan> Loan { get; set; }
但是,如果您在原文中注意到 public getter,我需要用另一个对象实例化每个对象:这是必需的,并且这些存储库对象没有无参数构造函数。
有什么建议吗?
整个对象看起来像:
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
}
有一种使用反射的解决方案,尽管它可能不是最干净的 OOP 解决方案。 System.Runtime 命名空间 FormatterServices.GetUninitializedObject() will create an instance without calling the constructor. There is a similar answer to this problem here.
中 FormatterService class 的方法为了使其适用于您的解决方案,您必须对代码进行一些更改。首先从你的泛型 class Property
声明中删除 new() 否则如果你尝试使用没有无参数构造函数的类型 T ,你总是会从编译器中得到一个错误。其次将此方法添加到您的 Property
class:
private T GetInstance()
{
return (T)FormatterServices.GetUninitializedObject(typeof(T)); //does not call ctor
}
它将return一个单元化的对象,但不会调用构造函数。
完整代码如下:
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中看看结果。
希望对您有所帮助。
可能会尝试类似的方法:
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);
}
}