Общее ограничение для конструктора со строковым аргументом? - PullRequest
3 голосов
/ 31 марта 2011

Как создать универсальный класс, который позволяет типам, у которых конструктор принимает один строковый аргумент, реализует ToString и реализует две функции, как показано ниже.

    class Convert<T>:ConverterBase
        where T:new()
    {

        public override object StringToField(string from)
        {
            try
            {
                return new T(from);
            }
            catch (ArgumentException exception)
            {
                ThrowConvertException(from, exception.Message);
                return null;
            }
        }

        public override string FieldToString(object from)
        {
            return from.ToString();
        }

    }

Примечание: ConvertBase - это абстрактный класс в библиотеке FileHelpers CSV Reader. У меня уже есть классы, соответствующие моим полям в csv, я не хотел создавать отдельные классы, которые наследуют порядок ConvertBase для использования с библиотекой FileHelpres.

Ответы [ 3 ]

2 голосов
/ 31 марта 2011

Нет способа использовать ограничение конструктора (new()) для ограничения чего-либо, кроме пустого конструктора. Однако один из способов обойти это - использовать лямбда-выражение Например

class Convert<T>:ConverterBase {
  private Func<string, T> _factory;
  public (Func<string, T> factory) {
    _factory = factory;
  }

  public override object StringToField(string from) {
    try {
      return _factory(from);
    } ...
  }
}

Теперь я могу создавать экземпляры Convert<T> и использовать лямбда-выражение для пересылки в конструктор типа

new Convert<Foo>(s => new Foo(s));

РЕДАКТИРОВАТЬ Реализация C # 2.0, так как OP застрял с 2.0

public delegate TResult Func<T, TResult>(T arg);

new Convert<Foo>(delegate (string s) { return new Foo(s); });
0 голосов
/ 31 марта 2011

Привет, вы можете создать базовый класс, который хранит функцию конвертера и реализует оба члена, после чего вы можете наследовать его и предоставлять только преобразование строки в объект

public abstract class Convert<T>:ConverterBase
{
    private Func<string, T> ConverterFunction {get;set;}

    protected Convert(Func<string, T> converterFunction)
    {
        ConverterFunction = converterFunction;
    }

    public override object StringToField(string from)
    {
        try
        {
            return ConverterFunction(from);
        }
        catch (ArgumentException exception)
        {
            ThrowConvertException(from, exception.Message);
            return null;
        }
    }

    public override string FieldToString(object from)
    {
        return from.ToString();
    }

}

Позже создайте несколько простых производныхклассы, например:

public class ConvertMyClass:ConverterBase<MyClass>
{
    public ConvertMyClass()
        :base(from => new MyClass(from)
    { 
    }
}

Надеюсь, это поможет :) Не забудьте загрузить последнюю стабильную версию с: http://teamcity.codebetter.com/viewLog.html?buildId=lastSuccessful&buildTypeId=bt66&tab=artifacts&guest=1

РЕДАКТИРОВАТЬ: Используя Reflection, вы можете попробовать:

class Convert<T>:ConverterBase
{

    public override object StringToField(string from)
    {
        try
        {
            return Activator.CreateInstance(typeof(T), from);
        }
        catch (ArgumentException exception)
        {
            ThrowConvertException(from, exception.Message);
            return null;
        }
    }

    public override string FieldToString(object from)
    {
        return from.ToString();
    }

}

ПРИМЕЧАНИЕ. Отражение медленное, поэтому вы должны принять это во внимание

0 голосов
/ 31 марта 2011

Вы не можете. Вы можете только создать ограничение, которое обеспечивает, чтобы у вашего класса был конструктор без параметров . Ограничение для этого - new(), как вы знаете.

ToString() доступно для каждого типа, поскольку оно определено для Object, и каждый тип наследуется от Object. Однако вы не можете знать или обеспечить, обеспечивает ли ваш тип собственную реализацию ToString().

Чтобы убедиться, что параметр типа реализует два конкретных метода, поместите их в интерфейс и ограничьте параметр типа этим интерфейсом, а ваш класс реализует этот интерфейс.

...