我们说我有以下内容:
public class DataType1
{
public DataType1() { }
public string Read() { return "dt1"; }
}
public class DataType2
{
public DataType2() { }
public string Read() { return "dt2"; }
}
实用类:
public class Logger<T>
{
public Logger() { }
}
然后,在我的主应用程序中:
class Program
{
static void Main(string[] args)
{
var test1 = new Logger<DataType1>();
test1.Read(); // I want this to equal "dt1";
var test2 = new Logger<DataType2>();
test2.Read(); // I want this to equal "dt2";
}
}
我意识到我正试图做一种协方差。但是,我无法从Logger中获取DataType1 / DataType2 继承 - 这将违反体系结构(即DataType1 / DataType2位于DAL,并且程序员需要通过Logger才能访问DAL )。
关于如何实现这一目标的任何想法?
感谢。
答案 0 :(得分:4)
使用界面:
public interface IDataType
{
string Read();
}
public class DataType1 : IDataType
{
public DataType1() { }
public string Read() { return "dt1"; }
}
public class DataType2 : IDataType
{
public DataType2() { }
public string Read() { return "dt2"; }
}
public class Logger<T> where T : IDataType, new()
{
IDataType dataType { get; set; }
public Logger() {
dataType = new T();
}
public string Read()
{
return dataType.Read();
}
}
class Program
{
static void Main(string[] args)
{
var test1 = new Logger<DataType1>();
test1.Read(); // I want this to equal "dt1";
var test2 = new Logger<DataType2>();
test2.Read(); // I want this to equal "dt2";
}
}
不过,我认为更好的做法是放弃仿制药:
public interface IDataType
{
string Read();
}
public class DataType1 : IDataType
{
public DataType1() { }
public string Read() { return "dt1"; }
}
public class DataType2 : IDataType
{
public DataType2() { }
public string Read() { return "dt2"; }
}
public class Logger
{
IDataType dataType { get; set; }
public Logger(IDataType dt) {
dataType = dt;
}
public string Read()
{
return dataType.Read();
}
}
class Program
{
static void Main(string[] args)
{
var dt1 = new DataType1();
var test1 = new Logger(dt1);
test1.Read(); // I want this to equal "dt1";
var dt2 = new DataType2();
var test2 = new Logger(dt2);
test2.Read(); // I want this to equal "dt2";
}
}
答案 1 :(得分:1)
使用接口:
public class DataType1 : IReadable
{
public DataType1() { }
public string Read() { return "dt1"; }
}
public class DataType2 : IReadable
{
public DataType2() { }
public string Read() { return "dt2"; }
}
public interface IReadable
{
string Read();
}
并强制泛型类型实现此接口:
public class Logger<T> where T : IReadable
您必须获得对执行Read
操作的实例的引用,然后您实际上可以对记录器本身进行委派Read
操作:
public class Logger<T> where T : IReadable
{
private readonly T _readable;
public Logger<T>(T readable)
{
this._readable = readable;
}
public string Read()
{
return this._readable.Read();
}
}
使用方法是:
var dt1 = new DataType1();
var dt2 = new DataType2();
var logger1 = new Logger<DataType1>(dt1);
var logger2 = new Logger(dt2); // can omit generic noise!
Console.WriteLine(logger1.Read()); // "dt1"
Console.WriteLine(logger2.Read()); // "dt2"
如果您想避免必须创建实例并将其传递给记录器,您可以在记录器中实例化它,但是您必须添加new()
约束,这意味着存在一个不带参数的公共构造函数,你甚至可以让记录器实现IReadable
本身:
public class Logger<T> : IReadable where T : IReadable, new()
{
private readonly T _readable;
public Logger<T>()
{
this._readable = new T();
}
public string Read()
{
return this._readable.Read();
}
}
使用方法是:
var logger1 = new Logger<DataType1>();
Console.WriteLine(logger1.Read()); // "dt1"
答案 2 :(得分:0)
正如@leppie所说,如果要在泛型实用程序类声明中添加约束。它可以解决这个问题。您需要通过构造函数或属性的使用为您的Logger类注入依赖。
比方说,您可以使用以下界面:
public interface IReader
{
public String Read();
}
我们希望DataType1和DataType2看起来像
public class DataType1:IReader
{
public String Read()
{
return "dt1";
}
}
您的实用程序类可能会变成:
public class Logger<T> where T:IReader
{
private T dataTypeInstance;
public Logger(T dataTypeInstance)
{
this.dataTypeInstance = dataTypeInstance;
}
public String Read()
{
return dataTypeInstance.Read();
}
}
它的Read方法只会调用DataType类的Read方法。
然后,我们可以从某种工厂获取DataType1和DataType2的实例 并尝试使用类似的东西:
var test1 = new Logger<DataType1>(dataType1);
var test2 = new Logger<DataType2>(dataType2);
test1.Read(); //will be dt1
test2.Read(); //will be dt2
或者,不是通过构造函数或实用程序类中的属性使用依赖项注入,而是可以使用反射和属性文件或(数据库存储的配置)以及is
运算符来获取正确的DataType实例使用。
答案 3 :(得分:0)
如果您无法使用界面,请尝试使用lambda表达式:
public class Logger<T> where T : new()
{
private Func<T, string> _readFunc;
private T _member;
public Logger(Func<T, string> readFunc)
{
_readFunc = readFunc;
_member = new T();
}
// Use this if you already have an instance of your data type
public Logger(Func<T, string> readFunc, T member)
{
_readFunc = readFunc;
_member = member;
}
public string Read()
{
return _readFunc(_member);
}
}
然后在你的应用中:
static void Main()
{
var test1 = new Logger<DataType1>(t => t.Read());
test1.Read(); // Will be equal "dt1";
var test2 = new Logger<DataType2>(t => t.Read());
test2.Read(); // Will be equal "dt2";
}