Xamarin.Android: 之前插入到 ArrayAdapter 中的项目再次找不到

Xamarin.Android: item previously inserted in ArrayAdapter is not found again

我继承了这个 Xamarin.Android 应用程序,但它有一些问题。

一个特定的错误涉及 ArrayAdapter<ProductListObject>,其中 ProductListObject 是子项目之间共享的常见 POCO(即 Android、Windows Phone 和 iOS);它只有几个属性(例如 Id)并覆盖 (.NET) Equals() 方法以实现结构相等:

public class ProductListObject
{
    public long Id { get; set; }

    public override bool Equals(object obj)
    {
        if (!(obj is ProductListObject))
        {
            return false;
        }

        return Id == (obj as ProductListObject).Id;
    }
}

问题是,每当我将此 ProductListObject 的实例放入 ArrayAdapter 中时,即使它们具有相同的 Id,我也无法再次找到它:

var p1 = new ProductListObject { Id = 1 };
var p2 = new ProductListObject { Id = 1 };

var areEqual = p1.Equals(p2); // returns True, as expected

var productAdapter = new ArrayAdapter<ProductListObject>(this, 0, new[] { p1 });
var position = productAdapter.GetPosition(p2); // returns -1 >:(

我的问题是:我必须做什么才能让我的 POCO 在内部使用 Xamarin.Android 依赖于 Java equals() 方法的类型(like ArrayAdapter; which delegates to List.indexOf(Object) )?

我尝试过的:

谢谢, 一月

当在 Android.Widget.ArrayAdapter 中使用时,.NET 对象似乎被包裹在 Java.Lang.Object 中。因此,在 productAdapter.GetPosition(...) 调用中使用的比较方法实际上是包装 Java.Lang.Object.

的 java Equals(Java.Lang.Object o) 方法

要在两个对象具有相同的 Id 时使 ProductListObject 解析为相同的索引,请使 ProductListObject 派生自 Java.Lang.Object,覆盖 Equals(Java.Lang.Object) 并将其转发给 .NET Equals(System.Object) 方法:

public class ProductListObject : Java.Lang.Object
{
    public long Id { get; set; }

    public override bool Equals(object obj) // Inherited from System.Object.
    {
        if (!(obj is ProductListObject))
        {
            return false;
        }

        return Id == (obj as ProductListObject).Id;
    }

    public override bool Equals (Java.Lang.Object o) // Inherited from Java.Lang.Object.
    {
        return this.Equals (o as System.Object);
    }
}

如果您无法从 Java.Lang.Object 继承 ProductListObject,另一种选择是实现您自己的代理 class:

public class ProductListObject
{
    public long Id { get; set; }

    public override bool Equals(System.Object obj)
    {
        if (!(obj is ProductListObject))
        {
            return false;
        }

        return Id == (obj as ProductListObject).Id;
    }
}

public class JavaProxy: Java.Lang.Object 
{
    public Object Object { get; private set; } 

    public JavaProxy(System.Object o)
    {
        Object = o;
    }

    public override bool Equals (Java.Lang.Object o)
    {
        var proxy = o as JavaProxy;
        if (o != null) {
            return Object.Equals (proxy.Object);
        }
        return base.Equals (o);
    }
}

// ...

var productAdapter = new ArrayAdapter<JavaProxy>(this, 0, new[] { new JavaProxy(p1) });
var position = productAdapter.GetPosition(new JavaProxy(p2)); 

它不像第一种方法那么干净,但它也有效。

我按照 Matt R 的建议做了,并创建了一个继承自 Java.Lang.Object 并委托给实际 .NET 对象的代理:

public class JavaObject<TValue> : Java.Lang.Object
{
    public readonly TValue Value;

    internal JavaObject(TValue value)
    {
        Value = value;
    }

    public override bool Equals(Java.Lang.Object that)
    {
        if (!(that is JavaObject<TValue>))
        {
            return false;
        }

        return Value.Equals((that as JavaObject<TValue>).Value);
    }

    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }
}

这不会将我与平台无关的 POCO 与 Android 实现联系起来,而且它不会强迫我锁定某些严格的继承树,这总是一个优点。

申请很简单:

var p1 = new JavaObject<ProductListObject>(new ProductListObject { Id = 1 });
var p2 = new JavaObject<ProductListObject>(new ProductListObject { Id = 1 });

var areEqual = p1.Equals(p2); // returns True, as expected

var productAdapter = new ArrayAdapter<JavaObject<ProductListObject>>(this, 0, new[] { p1 });
var position = productAdapter.GetPosition(p2); // returns 0!