具有字符串参数的构造函数的通用约束?

3
如何创建一个通用类,允许具有构造函数(使用一个字符串参数)并实现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读取器库中的一个抽象类。我已经有了与csv字段对应的类,不想创建继承ConvertBase的单独类以便与FileHelpres库一起使用。
3个回答

2

使用构造函数约束(new())无法将其约束为除空构造函数以外的任何内容。不过,可以通过使用 lambda 表达式来解决这个问题。例如

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>的实例,并使用lambda表达式转发到类型的构造函数

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

编辑:鉴于问题发布者只能使用C# 2.0,下面是C# 2.0的实现:

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

new Convert<Foo>(delegate (string s) { return new Foo(s); });

我被困在C#2.0中,我认为我不能使用Func<>。 - yesraaj
这只是一个委托。你可以自己创建它:public delegate TResult Func<out TResult>() - Daniel Hilgarth
@yesraaj 你可以自己定义Func<>并使用旧的C#委托语法。我在我的答案中更新了一个示例。 - JaredPar

0

你可以创建一个基类,它存储转换函数并实现两个成员。然后你可以继承它并只提供从字符串到对象的转换。

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 编辑:使用反射,你可以尝试:
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();
    }

}

注意:反射很慢,因此您必须考虑到这一点。


我的意图是完全消除像ConvertMyClass这样的类,只要Type T有一个带有一个字符串参数的构造函数,这样我就可以使用[FieldConverter(typeof(Convert<HasRequiredFns>))] - yesraaj
@yesraaj:所以你需要使用反射来获取带有一个字符串参数的构造函数,并使用Activator动态调用它,我刚刚更新了答案。 - Marcos Meli

0

不行。你只能创建一个强制执行你的类具有无参构造函数的约束。该约束为new(),你知道的。

ToString()在每个类型上都可用,因为它在Object上定义,并且每个类型都继承自Object。但是,你无法知道或强制执行你的类型是否提供了自己的ToString()实现。

为确保类型参数实现了两个特定方法,请将它们放入一个接口中,并将类型参数限制为该接口,并使你的类实现该接口。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接