通过引用传递索引器正在访问的泛型集合中对象的成员

本文关键字:泛型 访问 集合 成员 对象 引用 索引 | 更新日期: 2023-09-27 18:21:38

我在C#中创建了一个泛型集合的实例,需要通过引用一个方法来传递该集合中结构的一个成员。我可以使用泛型集合的索引器来选择要在方法中修改哪个对象的成员吗?我似乎得到了一个错误("无法修改'expression'的返回值,因为它不是一个变量"),但我得到的与此类似:

Deque<Card> deck_of_cards = new Deque<Card>();  // standard deck of 52 playing cards (structs)
ModifyRank( ref deck_of_cards[4].rank, 8);  // Changes the rank (field, int) of the 5th card to 8

我正在转换使用std::deque和全局方法的C++代码,我希望在语法方面尽可能多地保留它。有人知道这个问题的优雅解决方案吗?

通过引用传递索引器正在访问的泛型集合中对象的成员

不可能通过引用传递通过索引器获得的结构的字段。在这样的集合中修改结构的内容需要单独的get和set操作,因为索引器不能通过引用返回值(至少在C#中不能,这可能与无法验证的MSIL有关)。

具体问题最直接的解决方案是:

Deque<Card> deck_of_cards = new Deque<Card>();  // standard deck of 52 playing cards
var tmp = deck_of_cards[4];
ModifyRank( ref tmp.rank, 8);  // Changes the rank (int) of the 5th card to 8
deck_of_cards[4] = tmp;

在C#中不鼓励使用ref关键字传递参数。相反,假设Card是一个类,您可能需要更改方法的签名,以简单地传递卡片:

ModifyRank(deck_of_cards[4], 8); 

由于类是C#中的引用类型,ModifyRank将修改作为参数传递的卡的内容。

如果没有看到Card类,我不能确定,但我怀疑Cardrank属性是一个属性,而不是字段。换句话说,你有申报

public class Card
{
    public int rank { get; set; }
}

而不是

public class Card
{
    public int rank;
}

但是属性语法(我的第一个例子)实际上是语法糖,它被编译器重写为类似的东西

public class Card
{
    private int _rank;
    public int get_rank()
    {
        return rank;
    }
    public int set_rank(int rank)
    {
        _rank = rank;
    }
}

这意味着Card上的rank属性根本不是int,而是两个方法的包装器。由于rank不是int,因此不能通过引用传递它。

现在是优雅的解决方案:

如果ModifyRank方法只设置其ref参数的值,则可以将第二行代码简化为

deck_of_cards[4].rank = 8;

这对任何读者来说都要清楚得多。如果你的ModifyRank方法正在做一些特殊的事情,你可以把这个扩展方法添加到一些静态类中:

public static void ModifyRank(this Card c, int newRank)
{
    int rank = c.rank;
    ModifyRank(ref rank, newRank);
    c.rank = rank;
}

这允许您用替换第二行

deck[4].ModifyRank(8);

尽管.net泛型集合不能很好地支持使用可变结构,但如果您设计自己的集合,就可以使它们有效地支持可变结构。我建议如下模式(假设对象类似于EnhancedList<T>:

//委托类型定义--应该放在某个位置delegate ActionByRef<T1>(参考T1 p1);delegate ActionByRef<T1、T2>(参考T1 p1、参考T2 p2);delegate ActionByRef<T1、T2、T3>(参考T1 p1,参考T2 p2,参考T3 p3);//EnhancedList<T>类型:项目[](_I);//数组以容纳实际项目void ActOnItem(int索引,ActionByRef<T>proc){proc(ref_items[index]);}void ActOnItem<PT1>(int index,ActionByRef<T,PT1>proc,ref PT1 p1){proc(ref_items[index],p1);}void ActOnItem<PT1、PT2>(int index,ActionByRef<T,PT1,PT2>proc,参考PT1 p1,参考PT2 p2){proc(ref _items[index],ref p1,ref p2);}

使用这样的方法,可以将集合中的项通过ref传递给任何所需的代码。没有办法处理可变泛型有点烦人,但这种方法允许任意的真正的引用传递语义,前提是定义具有足够参数的ActOnItem变体。