C#中无法向BlockingCollection添加Tuple:CS1503错误求助
问题:CS1503错误:Tuple类型不匹配
我正在开发基于C#的实时视频目标检测项目,用BlockingCollection管理检测目标的边界框列表,每个边界框详情存储在Tuple中。但尝试向集合添加新Tuple时触发CS1503错误。
BlockingCollection定义
BlockingCollection<Tuple<int, int, int, int, string, string, Scalar, DateTime>> ObjectDetectionBbox = new BlockingCollection<Tuple<int, int, int, int, string, string, Scalar, DateTime>>();
添加Tuple的代码
ObjectDetectionBbox.Add(Tuple.Create( topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y, className, trackedName, classColor, bboxTimestamp ));
错误信息
Error CS1503 Argument 1: cannot convert from 'System.Tuple<int, int, int, int, string, string, OpenCvSharp.Scalar, System.Tuple<System.DateTime>>' to 'System.Tuple<int, int, int, int, string, string, OpenCvSharp.Scalar, System.DateTime>'
错误提示显示Tuple的最后一个元素是Tuple<DateTime>,但代码中最后一个元素是DateTime类型,且已确认bboxTimestamp确实为DateTime,不清楚错误原因,寻求解决方法。
完整代码参考
public async Task Main(System.Windows.Controls.Image imageControl, CancellationToken token) { BlockingCollection<Tuple<int, int, int, int, string, string, Scalar, DateTime>> ObjectDetectionBbox = new BlockingCollection<Tuple<int, int, int, int, string, string, Scalar, DateTime>>(); BlockingCollection<Tuple<Mat, DateTime>> frameBuffer = new BlockingCollection<Tuple<Mat, DateTime>>(); // Our new frame buffer string cameraUrl = "http://cam1.infolink.ru/mjpg/video.mjpg"; //string cameraUrl = "http://hotel-seerose.dyndns.org:8001/cgi-bin/faststream.jpg?stream=full&fps=0"; string URLreturnBbox = "http://localhost:8003/api/v1/camera/get_frame"; // Updated endpoint URL await initializeRunServer(cameraUrl); var idFaceDictionary = new ConcurrentDictionary<long, object>(); var classNames = await GetClassNames(); var colorList = InitColorList(classNames.Count); Task processFrameTask = Task.Run(() => ProcessTask(imageControl, token, URLreturnBbox, classNames, colorList,idFaceDictionary, ObjectDetectionBbox)); // Create video source MJPEGStream stream = new MJPEGStream(cameraUrl); // New frame event handler stream.NewFrame += (sender, eventArgs) => { // Convert AForge.NET's Bitmap to OpenCvSharp's Mat Bitmap bitmap = (Bitmap)eventArgs.Frame.Clone(); Mat frame = OpenCvSharp.Extensions.BitmapConverter.ToMat(bitmap); // Get bbox info from ObjectDetectionBbox, if any while (ObjectDetectionBbox.TryTake(out var bbox)) // Replace if with while to draw all available bounding boxes { // Ensure we only proceed if there is a detection and a valid class name. if (!string.IsNullOrEmpty(bbox.Item5)) { if (bbox.Item5 == "person" && bbox.Item6 != null) // Display if person is detected { DrawPerson( frame, bbox.Item1, bbox.Item2, bbox.Item3, bbox.Item4, bbox.Item6, bbox.Item7 ); } else { Cv2.Rectangle(frame, new OpenCvSharp.Point(bbox.Item1, bbox.Item2), new OpenCvSharp.Point(bbox.Item1 + bbox.Item3, bbox.Item2 + bbox.Item4), bbox.Item7, 1); var caption = bbox.Item5; Cv2.PutText(frame, caption, new OpenCvSharp.Point(bbox.Item1, bbox.Item2), HersheyFonts.HersheyComplex, 1, bbox.Item7, 1); } } } // Process and display the frame Application.Current.Dispatcher.Invoke(() => { UpdateDisplay(frame, imageControl); }); }; // Start video capture stream.Start(); // Wait until cancellation is requested while (!token.IsCancellationRequested) { await Task.Delay(20); } // Stop video capture stream.SignalToStop(); stream.WaitForStop(); } public async Task ProcessTask(System.Windows.Controls.Image imageControl, CancellationToken token, string URLreturnBbox, IDictionary<int, string> classNames, List<Scalar> colorList, ConcurrentDictionary<long, object> idFaceDictionary, BlockingCollection<Tuple<int, int, int, int, string, string, Scalar, DateTime>> ObjectDetectionBbox) { while (!token.IsCancellationRequested) { if (RunOTModel && ObjectTracking) { await GetObjectDetectionBbox(URLreturnBbox, classNames, colorList, idFaceDictionary, ObjectDetectionBbox); } } } private async Task GetObjectDetectionBbox(string boundingBoxesUrl, IDictionary<int, string> classNames, List<Scalar> colorList, ConcurrentDictionary<long, object> idFaceDictionary, BlockingCollection<Tuple<int, int, int, int, string, string, Scalar, DateTime>> ObjectDetectionBbox) { var resultsList = await RunYolo(boundingBoxesUrl); // New dictionary to keep track of names already assigned var assignedNames = new ConcurrentDictionary<string, object>(); foreach (var results in resultsList) { if (!results.ContainsKey("class_")) continue; var classIndex = int.Parse(results["class_"].ToString()); var className = classNames[classIndex]; var classColor = colorList[classIndex]; var topLeft = new OpenCvSharp.Point((long)results["x"], (long)results["y"]); var bottomRight = new OpenCvSharp.Point((long)results["w"], (long)results["h"]); string trackedName = null; long trackId = 0; // initialize with default value bool hasTrackId = results.ContainsKey("track_id"); DateTime bboxTimestamp = DateTime.Parse(results["timestamp"].ToString()); if (hasTrackId) { trackId = (long)results["track_id"]; } if (OTFaceRecognition && hasTrackId && className == "person" && !idFaceDictionary.ContainsKey(trackId)) { if (results.ContainsKey("result") && results["result"] != null) { var resultStr = results["result"].ToString(); // Check if this name has not been assigned already if (!string.IsNullOrEmpty(resultStr) && !assignedNames.ContainsKey(resultStr)) { // Remove any existing entries with the same value foreach (var kvp in idFaceDictionary.Where(kvp => kvp.Value.Equals(resultStr)).ToList()) { idFaceDictionary.TryRemove(kvp.Key, out _); } // Add the new entry idFaceDictionary.TryAdd(trackId, resultStr); // Add this name to the assigned names assignedNames[resultStr] = new object(); } } } if (OTFaceRecognition && hasTrackId) { trackedName = idFaceDictionary.ContainsKey(trackId) ? $"{idFaceDictionary[trackId]} - ID {results["track_id"]}" : null; } ObjectDetectionBbox.Add(Tuple.Create( topLeft.X, // int topLeft.Y, // int bottomRight.X - topLeft.X, // int bottomRight.Y - topLeft.Y, // int className, // string trackedName, // string classColor, // Scalar bboxTimestamp // DateTime )); } }
解决方法
原因分析
.NET的Tuple.Create方法仅支持最多7个泛型参数,当传入第8个参数时,它会自动将最后一个参数包装为嵌套的Tuple<T>,这就是错误中显示最后一个元素为Tuple<DateTime>的原因。
方案1:改用ValueTuple(推荐)
C# 7.0及以上支持的ValueTuple无元素数量限制,语法更简洁,性能更优:
- 修改
BlockingCollection定义:BlockingCollection<(int X, int Y, int Width, int Height, string ClassName, string TrackedName, Scalar Color, DateTime Timestamp)> ObjectDetectionBbox = new BlockingCollection<(int, int, int, int, string, string, Scalar, DateTime)>(); - 添加元素时直接使用值元组语法:
ObjectDetectionBbox.Add(( topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y, className, trackedName, classColor, bboxTimestamp )); - 读取元素时可直接通过命名访问(如
bbox.ClassName),比Item5可读性高很多。
方案2:手动创建8元素Tuple
如果必须使用Tuple,需显式实例化Tuple<T1,T2,T3,T4,T5,T6,T7,T8>,而非依赖Tuple.Create:
ObjectDetectionBbox.Add(new Tuple<int, int, int, int, string, string, Scalar, DateTime>( topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y, className, trackedName, classColor, bboxTimestamp ));
内容的提问来源于stack exchange,提问作者Captain C
相关产品推荐
相关产品推荐

