C#中的泛型类

时间:2015-02-11 05:45:40

标签: c#

我们说我有以下内容:

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 )。

关于如何实现这一目标的任何想法?

感谢。

4 个答案:

答案 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";
}