2015-02-11 2 views
0

Допустим, у меня есть следующие:Общий класс в C#

public class DataType1 
{ 
    public DataType1() { } 

    public string Read() { return "dt1"; } 
} 

public class DataType2 
{ 
    public DataType2() { } 

    public string Read() { return "dt2"; } 
} 

и утилиту класса:

Затем в моем главном приложении:

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

я понимаю, что Я пытаюсь сделать вид ковариации. Тем не менее, я не могу DataType1/DataType2 наследовать от Logger - это было бы против архитектуры (т. Е. DataType1/DataType2 находятся в DAL, и программисты должны пройти через Logger, чтобы добраться до DAL).

Любые мысли о том, как я мог это сделать?

Спасибо.

+0

класс 'Logger где T: SomeInterfaceWithReadMethod' – leppie

ответ

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" 
+0

спасибо, после нескольких бессонных ночей и сроки, я чувствовал, что легче спросить: «Потому что мой мозг просто мертв ... :) – a11smiles

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

Btw, я думаю, что лучше практика будет уронить дженерики:

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"; 
    } 
} 
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(); 

    } 
} 

И его метод чтения просто вызовет метод чтения ваших данных Тип класса.

Мы можем тогда, получить экземпляры 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.

0

Если вы наклоненная использовать интерфейс, попробуйте использовать лямбда exprestion:

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