C# 字典<;T、 Func>;:如何使用T作为Func';什么是泛型?

C# 字典<;T、 Func>;:如何使用T作为Func';什么是泛型?,c#,dictionary,generics,func,C#,Dictionary,Generics,Func,我不知道如何表达清楚 我有这个界面: interface IConverter { Dictionary<Type, Func<string, object>> ConversionMethods { get; } } 这取决于您可以更改签名的程度,但至少接口可以使用泛型类型强制执行。如何添加强类型转换器则是实现者的责任,而不是调用者的责任 实现本身可以使用任何构造来提供转换器。事件if…else,但要在引擎盖下使用字典,可以使用类型为dictionary的字典

我不知道如何表达清楚

我有这个界面:

interface IConverter
{
    Dictionary<Type, Func<string, object>> ConversionMethods { get; }
}

这取决于您可以更改签名的程度,但至少接口可以使用泛型类型强制执行。如何添加强类型转换器则是实现者的责任,而不是调用者的责任

实现本身可以使用任何构造来提供转换器。事件if…else,但要在引擎盖下使用字典,可以使用类型为
dictionary
的字典,其中可以添加强类型转换器。下面的示例使用helper
set
函数来确保以预期的方式设置字典

interface IConverter
{
    Func<string,T> GetConverter<T>(); //the method returned is always strongly typed, so the caller is never responsible for type checking
}

enum A{AA,AB,AC}    
enum B{BA, BB, BC}

class blah : IConverter
{
    public Func<string,T> GetConverter<T>()
    {
        if(methods.TryGetValue(typeof(T), out var fn)) //side note, out var fn will not work in older visual studio versions. In that case declare fn before this line
            return (Func<string,T>)fn; //the set<T> method ensures that this conversion is safe
        throw new NotImplementedException(); 
    }

    public blah()
    {
        set<A>(s => s == "AA" ? A.AA : s == "AB" ? A.AB : A.AC); //copied from the example. Enum.Parse could perhaps be used instead
        set<B>(s => s == "BA" ? B.BA : s == "BB" ? B.BB : B.BC);
    }

    Dictionary<Type, Delegate> methods= new Dictionary<Type, Delegate>(); // Delegate can be used as a type to handle all lambda's. It's the implementers responsibility to handle with care. Something like the set<T> helper method is recommended

    void set<T>(Func<string,T> fn) //helper method to assign the strongly typed methods to the specific type
    {
        methods[typeof(T)] = fn;
    }
}

static void blahah()
{
    new blah().GetConverter<A>()("123");
}
接口IConverter
{
Func GetConverter();//返回的方法始终是强类型的,因此调用方从不负责类型检查
}
枚举A{AA,AB,AC}
枚举B{BA,BB,BC}
类blah:IConverter
{
公共函数GetConverter()
{
if(methods.TryGetValue(typeof(T),out-var-fn))//请注意,out-var-fn在较旧的visual studio版本中不起作用。在这种情况下,请在此行之前声明fn
return(Func)fn;//set方法确保此转换是安全的
抛出新的NotImplementedException();
}
公共废话
{
set(s=>s==“AA”?A.AA:s==“AB”?A.AB:A.AC);//可以使用从示例中复制的。Enum.Parse
集合(s=>s==“BA”?B.BA:s==“BB”?B.BB:B.BC);
}
Dictionary methods=new Dictionary();//委托可以用作处理所有lambda的类型。谨慎处理是实现者的责任。建议使用类似set helper的方法
void set(Func fn)//将强类型方法指定给特定类型的helper方法
{
方法[类型(T)]=fn;
}
}
静态无效blahah()
{
新blah().GetConverter()(“123”);
}

这有点复杂,但它可以工作

首先,您需要将转换
Func
s封装在类中,这样您就可以更轻松地处理它们,而不必公开它们所有不同的类型参数。然后,您需要定义接口或基类来隐藏各种泛型参数,使它们不会引起问题,并允许您将不同的转换器放在同一个集合中。然后,您将需要各种转换器的方法来表示它们使用的类型,而不直接使用这些类型参数。然后,您只需要使用一个方法将其封装在一个类中,该方法将根据需要找到正确的转换器

我陪你走过去

首先,这个基类将是我们处理转换器的方式,不用担心它的泛型类型参数,但仍然知道它使用什么类型

public abstract class OneWayTypeConverterBase : IConvertFromType, IConvertToType
{
    public abstract Type AcceptsType { get; }
    public abstract Type ReturnsType { get; }
}
现在我们从基类继承。这是执行转换实际工作的类;您可以使用lambda对其进行实例化,该lambda执行您需要的任何转换操作。请注意,它实现了我们上面定义的属性

public class OneWayTypeConverter<TSource, TTarget> : OneWayTypeConverterBase
{
    public OneWayTypeConverter(Func<TSource, TTarget> conversionMethod)
    {
        _conversionMethod = conversionMethod;
    }

    public override Type AcceptsType => typeof(TSource);
    public override Type ReturnsType => typeof(TTarget);

    private readonly Func<TSource, TTarget> _conversionMethod;

    public TTarget Convert(TSource sourceObject)
    {
        return _conversionMethod(sourceObject);
    }
}
现在,您可以这样设置它:

var converter = new TypeConverter(new List<OneWayTypeConverterBase>
{
    new OneWayTypeConverter<int, string>(x => $"The number was {x}"),
    new OneWayTypeConverter<int, bool>(x => x != 0),
    new OneWayTypeConverter<bool, string>(x => $"The bool was {x}")
});
var result = converter.ConvertType<int, string>(4);
var converter=新类型转换器(新列表
{
新的OneWayTypeConverter(x=>$“编号为{x}”),
新的单向类型转换器(x=>x!=0),
新的OneWayTypeConverter(x=>$“bool是{x}”)
});
当你需要它时,你可以这样使用它:

var converter = new TypeConverter(new List<OneWayTypeConverterBase>
{
    new OneWayTypeConverter<int, string>(x => $"The number was {x}"),
    new OneWayTypeConverter<int, bool>(x => x != 0),
    new OneWayTypeConverter<bool, string>(x => $"The bool was {x}")
});
var result = converter.ConvertType<int, string>(4);
var result=converter.ConvertType(4);

如果可能的话,您可以发布一个示例代码片段,说明您打算如何访问这样一个虚构的字典吗?@Kilazur,“是否可以替换Func的泛型类型中的类型”。。。你的意思是要替换
对象吗?
?在编译时是不可能的。目前发布的示例显示了如何填充字典。但是在那段代码中,使用
object
dynamic
键入函数不会像你说的那样“令人讨厌”,是吗?我想,一旦你试图从字典中阅读,当你必须转换时,恼人的部分就会随之而来——请你也举一个这样用法的例子好吗?具体地说,我想知道您是否知道在compiletime检索的类型(在这种情况下,您可能不需要字典),或者是否只知道在运行时检索的类型(在这种情况下,我无法想象您如何安全地使用results类型)。这与我以前尝试过的方法有关。你可以靠得很近,但这条路不行。基本上,可以使用泛型来强制执行您所追求的需求,但不仅仅是使用现有类型;您将需要一些自定义类型。我会看看我是否能把一个例子提炼成可以作为答案的东西。很有趣,但是接口必须有一种方法来返回所有的转换方法,所以我可以在其他地方使用它们,而不必事先知道它们的类型。@Kilazur这是不可能的,除非您使用dynamic或object,或者可能使用一个通用的接口types@Zbigniew这也是我的猜测,您可以让接口/类也在一个单独的方法中返回所有委托(字典值)。就我个人而言,我会将对转换方法的直接调用保持为强类型。但是,如果目标是在转换器周围增加更多的额外包装,可能会更可取。这实际上看起来几乎完美。唯一的缺点是IEnumerable允许对单个类型使用多个方法,但这是可以管理的。我稍后会测试它,但它看起来很好。当您转换为字典时,您可以很容易地检查同一类型的多个转换器,并引发异常,或者您可以提供一种方法来一次添加一个转换器,并在添加新转换器之前检查该类型的现有转换器。后者将是我首选的方法,但构造函数方法仍然很好,因此您可以快速设置
TypeConverter
,因此我可能会同时实现这两种方法。如果您愿意,我可以将其添加到我的代码示例中?啊,它实际上不适合我;我想要的似乎不可能,