You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:37:50