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

时间:2012-01-26 00:59:22

标签: c# generics collections

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

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 ++代码,我希望尽可能多地保留语法。有谁知道这个问题的优雅解决方案?

4 个答案:

答案 0 :(得分:2)

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

ModifyRank(deck_of_cards[4], 8); 

由于C#中的类为reference typesModifyRank将修改作为参数传递的卡的内容。

答案 1 :(得分:2)

不可能通过引用传递通过索引器得到的struct的字段。要修改此类集合中结构的内容,需要单独的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;

答案 2 :(得分:0)

没有看到Card类,我无法确定,但我怀疑rank的{​​{1}}属性是属性,而不是字段。换句话说,你有声明

Card

而不是

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; } } 上的rank属性根本不是Card,而是两个方法的包装器。由于int不是rank,因此您无法通过引用传递它。

现在优雅的解决方案:

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

ModifyRank

对任何读者来说都更清楚。如果您的deck_of_cards[4].rank = 8; 方法正在执行某些特殊操作,则可以将此extension method添加到某个静态类:

ModifyRank

这允许您用

替换第二行
public static void ModifyRank(this Card c, int newRank)
{
    int rank = c.rank;
    ModifyRank(ref rank, newRank);
    c.rank = rank;
}

答案 3 :(得分:0)

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

// Delegate type definitions--should go somewhere
  delegate ActionByRef<T1>(ref T1 p1);
  delegate ActionByRef<T1,T2>(ref T1 p1, ref T2 p2);
  delegate ActionByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, ref T3 p3);
// Code within the EnhancedList<T> type:
  T _items[];  // Array to hold actual items
  void ActOnItem(int index, 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, 
                          ref PT1 p1, ref PT2 p2)
    { proc(ref _items[index], ref p1, ref p2); }

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