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

Xamarin中使用字节数组作为ConcurrentHashMap键值时不符合预期

问题原因拆解

这个问题我之前在Xamarin Android开发中也碰到过,核心是C#与Java跨绑定层的数组对象映射逻辑在搞鬼:

  • Java的ConcurrentHashMap是基于对象的equals()和hashCode()来匹配键的,而Java原生的byte[]数组的equals()方法是引用相等判断——只有当两个数组是同一个内存引用时才会返回true,不会对比数组内容。
  • 在Xamarin中,当你把C#的byte[]传递给Java方法(比如Put和Get)时,绑定层会自动把C#数组转换成Java的byte[]实例。但这里有个坑:每次传递同一个C#数组变量到Java层时,绑定层可能会生成一个全新的Java数组对象。也就是说,你调用map.Put(key, data)时传入的Java数组,和调用map.Get(key)时传入的Java数组,是两个完全不同的Java对象引用。
  • 这就导致ConcurrentHashMap在查找时,找不到和传入的新数组引用匹配的键,自然返回null;而通过map.Keys()遍历拿到的k是当初Put时存储的那个Java数组引用,用它调用Get当然能匹配到对应的值。
可行解决方案

针对这个问题,有几种不同的解决思路,你可以根据自己的场景选择:

1. 直接使用Java原生数组作为键

绕过C#数组的跨绑定转换问题,直接创建Java层的byte[]来作为键和值:

// 直接创建Java byte数组
var javaKey = new byte[] { 1, 2, 3 }; // Xamarin会自动识别为Java数组
var javaData = new byte[] { 1, 2, 3, 4, 5 };
map.Put(javaKey, javaData);
var val = map.Get(javaKey); // 此时能正确获取到对应值

或者用Java.Util.Arrays工具类来转换C#数组,确保前后用的是同一个Java数组:

var csharpKey = new byte[] { 1, 2, 3 };
var javaKey = Java.Util.Arrays.ToByteArray(csharpKey);
var javaData = Java.Util.Arrays.ToByteArray(new byte[] { 1, 2, 3, 4, 5 });

map.Put(javaKey, javaData);
var val = map.Get(javaKey); // 正确获取值

2. 自定义键类,基于内容匹配

如果需要根据数组内容来匹配键(而不是引用),可以自定义一个继承自Java.Lang.Object的包装类,重写equals()和hashCode()方法,基于数组内容来实现判断:

public class ByteArrayKey : Java.Lang.Object
{
    private readonly byte[] _innerBytes;

    public ByteArrayKey(byte[] bytes)
    {
        _innerBytes = bytes;
    }

    // 重写equals,基于数组内容判断相等
    public override bool Equals(Java.Lang.Object other)
    {
        if (other is ByteArrayKey otherKey)
        {
            return Java.Util.Arrays.Equals(_innerBytes, otherKey._innerBytes);
        }
        return false;
    }

    // 重写hashCode,基于数组内容生成哈希值
    public override int HashCode()
    {
        return Java.Util.Arrays.HashCode(_innerBytes);
    }
}

使用方式也很简单:

var key = new ByteArrayKey(new byte[] { 1, 2, 3 });
var data = new byte[] { 1, 2, 3, 4, 5 };
map.Put(key, data);
var val = map.Get(key); // 正确获取对应值

3. 改用C#原生的并发字典

如果你的场景不需要和Java代码交互,完全可以抛弃Java的ConcurrentHashMap,改用C#自己的ConcurrentDictionary<byte[], byte[]>,并自定义一个基于数组内容的相等比较器:

// 自定义数组内容比较器
public class ByteArrayEqualityComparer : IEqualityComparer<byte[]>
{
    public bool Equals(byte[] x, byte[] y)
    {
        if (x == null || y == null) return x == y;
        return x.SequenceEqual(y);
    }

    public int GetHashCode(byte[] obj)
    {
        if (obj == null) return 0;
        int hash = 17;
        foreach (byte b in obj)
        {
            hash = hash * 31 + b;
        }
        return hash;
    }
}

// 使用示例
var concurrentDict = new ConcurrentDictionary<byte[], byte[]>(new ByteArrayEqualityComparer());
var key = new byte[] { 1, 2, 3 };
var data = new byte[] { 1, 2, 3, 4, 5 };
concurrentDict.TryAdd(key, data);
var val = concurrentDict[key]; // 正确获取值

内容的提问来源于stack exchange,提问作者Luis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:35:54