C# 存储不同泛型类型的列表
我知道这是一个经常讨论的话题,因为我发现很多帖子都在谈论它。不幸的是,它们似乎都没有解决我的问题,要么是因为我不理解解决方案,要么是因为我把我的问题复杂化了 我在现有的TPL数据流库的基础上实现了一个简单的数据流。为了便于测试,我想向其构造函数提供一个块连接列表,以便它自动创建所有块及其连接。为此,我创建了以下类:C# 存储不同泛型类型的列表,c#,generics,tpl-dataflow,C#,Generics,Tpl Dataflow,我知道这是一个经常讨论的话题,因为我发现很多帖子都在谈论它。不幸的是,它们似乎都没有解决我的问题,要么是因为我不理解解决方案,要么是因为我把我的问题复杂化了 我在现有的TPL数据流库的基础上实现了一个简单的数据流。为了便于测试,我想向其构造函数提供一个块连接列表,以便它自动创建所有块及其连接。为此,我创建了以下类: internal class DataflowBlockConnection<TInput, TOutput> : IDataflowBlockConnection {
internal class DataflowBlockConnection<TInput, TOutput> : IDataflowBlockConnection
{
public ISourceBlock<TOutput> Source { get; set; }
public ITargetBlock<TInput> Target { get; set; }
}
不幸的是,这不会编译,因为我在接口中没有关于源和目标的信息,这将允许我将源连接到目标。这就是其他线程与此不同的地方。通过这种设计,我可以拥有一个具有自己输入和输出类型的不同连接的列表,但我无法访问每个块,因为我需要关于TInput和TOutput的信息。我错过什么了吗
编辑:
在@Enigmativity的评论之后,我减少了我的问题,以便更容易理解
我有两种类型的类,源块和目标块。它们都实现IDataflowBlock接口,因为它们都是不同类型的块。它们都接收一个泛型类型(TInput或TOutput),可以是任何类型
源块可以链接到目标块,但该方法仅适用于源块
以下是简化类(这是TPL数据流的一个简短转录,仅基于我的问题):
为了能够从IDataflowBlockConnection访问源和目标,而无需将TInput和TOutput关联到它(这会破坏具有不同TInput和TOutput类型的列表的可能性),我将其更改为:
internal interface IDataflowBlockConnection
{
ISourceBlock<TOutput> GetSource<TOutput>();
ITargetBlock<TInput> GetTarget<TInput>();
}
内部接口IDataflowBlockConnection
{
ISourceBlock GetSource();
ITargetBlock GetTarget();
}
现在我正在考虑用反射调用这些方法,这(我认为,因为尚未实现)将解决我的问题。我的问题是:我是否使解决方案复杂化了?有没有一个优雅的解决方案是我没有看到的?我在寻找解决问题的方法时,无意中发现了UppDynamic。一种解决方案是使用反射在运行时将类型注入方法,正如@Theodor Zoulias所建议的那样。另一个解决方案是使用动态,尽管这仍然是一个有争议的话题,因为它取决于具体情况。这是一个好方法吗?我无意中发现了UppDynamic,正在寻找解决问题的方法。一种解决方案是使用反射在运行时将类型注入方法,正如@Theodor Zoulias所建议的那样。另一个解决方案是使用动态,尽管这仍然是一个有争议的话题,因为它取决于具体情况。这个好用吗?我承认我已经有一段时间没看这个东西了,所以我可能遗漏了什么。你的界面可以是通用的吗
IDataflowBlockConnection
?如果我的接口是泛型接口,则会强制TInput或TOutput的值在其整个生命周期内保持不变,这意味着我失去了拥有多类型列表的能力:/这是使用反射的选项吗?当然,这是使用反射的选项。我想避免它,但如果考虑到目前的情况,这是最好的选择,它很好,我认为不经过思考是不可能的,因为块实现的唯一非通用接口是,它不支持将它们链接到其他块。我承认我已经有一段时间没有研究过这些东西了,所以我可能错过了什么。你的界面可以是通用的吗IDataflowBlockConnection
?如果我的接口是泛型接口,则会强制TInput或TOutput的值在其整个生命周期内保持不变,这意味着我失去了拥有多类型列表的能力:/这是使用反射的选项吗?当然,这是使用反射的选项。我想避免它,但如果考虑到具体情况,它是最好的选择,我认为不经过思考是不可能的,因为块实现的唯一非通用接口是,它不支持将它们链接到其他块。dynamic
在处理外部对象(如XML、JSON或DBs)时很好,这些对象的名称不断变化。你在对付C。处理C#几乎总是有比动态更好的方法。那么,你对我的问题有什么建议呢?我很想给你一个答案,但问题还不完整。我看不到块连接列表的定义。我没有看到任何构造函数。我不知道什么CreateStructure
被覆盖,从哪里覆盖。我没有看到ConnectBlocks
。你能提供一个完整的,我可以复制,粘贴,并看到在我的环境中没有编译的代码。然后我可以重构并使其工作。然后我可以给你一个答案。你没有其他答案的原因是这个问题不完整。你能帮我吗?我更新了我的问题,所以它提供了更多的细节。我希望它是有帮助的:)dynamic
在处理外部对象(如XML、JSON或DBs)时很好,这些对象的名称不断变化。你在对付C。处理C#几乎总是有比动态更好的方法。那么,你对我的问题有什么建议呢?我很想给你一个答案,但问题还不完整。我看不到块连接列表的定义。我没有看到任何构造函数。我不知道什么CreateStructure
被覆盖,从哪里覆盖。我没有看到ConnectBlocks
。你能提供一个完整的,我可以复制,粘贴,并看到在我的环境中没有编译的代码。然后我可以重构并使其工作。然后我可以给你一个答案。你没有其他答案的原因是因为这个问题
internal interface IDataflowBlock
{
}
internal interface ISourceBlock<out TOutput> : IDataflowBlock
{
void LinkTo(ITargetBlock<TOutput> target);
}
internal interface ITargetBlock<in TInput> : IDataflowBlock
{
}
internal interface IDataflowBlockConnection
{
}
internal class DataflowBlockConnection<TInput, TOutput> : IDataflowBlockConnection
{
public ISourceBlock<TOutput> Source { get; set; }
public ITargetBlock<TInput> Target { get; set; }
}
// Two blocks that act as source, consuming types int and char
ISourceBlock<int> sourceInt = new SourceBlock<int>();
ISourceBlock<char> sourceChar = new SourceBlock<char>();
// One block that acts as target, receiving type string
ITargetBlock<string> targetString = new TargetBlock<string>();
// Pipeline structure:
// sourceInt -> targetString
// sourceChar -> targetString
DataflowBlockConnection<string, int> connection1 = new DataflowBlockConnection<string, int>
{
Source = sourceInt,
Target = targetString
};
DataflowBlockConnection<string, char> connection2 = new DataflowBlockConnection<string, char>
{
Source = sourceChar,
Target = targetString
};
List<IDataflowBlockConnection> blockConnections = new List<IDataflowBlockConnection>
{
connection1, connection2
};
foreach (IDataflowBlockConnection connection in blockConnections)
{
// Does not compile, since IDataflowBlockConnection has no information about Source and Target.
connection.Source.LinkTo(Target);
}
internal interface IDataflowBlockConnection
{
ISourceBlock<TOutput> GetSource<TOutput>();
ITargetBlock<TInput> GetTarget<TInput>();
}