В C# Несколько Индексаторов

возможно ли иметь что-то вроде следующего:

class C
{
    public Foo Foos[int i]
    {
        ...
    }

    public Bar Bars[int i]
    {
        ...
    }
}

если нет, то каковы некоторые из способов, которыми я могу этого достичь? Я знаю, что могу создавать функции getFoo(int i) и getBar(int i), но я надеялся сделать это со свойствами.

7 ответов


нет в C# нет.

однако вы всегда можете возвращать коллекции из свойств следующим образом:

public IList<Foo> Foos
{
    get { return ...; }
}

public IList<Bar> Bars
{
    get { return ...; }
}

IList имеет индексатор, поэтому вы можете написать следующее:

C whatever = new C();
Foo myFoo = whatever.Foos[13];

на строках " return ...; "вы можете вернуть все, что реализует IList, но вы можете вернуть оболочку только для чтения вокруг вашей коллекции, см. Метод AsReadOnly ().


Это из спецификации C# 3.0

" перегрузка индексаторов позволяет классу, структуре или интерфейсу объявлять несколько индексаторов при условии, что их подписи уникальны в пределах этого класса, структуры или интерфейса."

public class MultiIndexer : List<string>  
{
    public string this[int i]
    {
        get{
            return this[i];
        }
    }
    public string this[string pValue]
    {
        get
        {
            //Just to demonstrate
            return this.Find(x => x == pValue);  
        }
    }      
}

попробуйте мой класс IndexProperty, чтобы включить несколько индексаторов в том же классе

http://www.codeproject.com/Tips/319825/Multiple-Indexers-in-Csharp


есть способ.. если вы определяете 2 новых типа, чтобы выделить компилятор для различения двух разных сигнатур...

  public struct EmployeeId
  { 
      public int val;
      public EmployeeId(int employeeId) { val = employeeId; }
  }
  public struct HRId
  { 
      public int val;
      public HRId(int hrId) { val = hrId; }
  }
  public class Employee 
  {
      public int EmployeeId;
      public int HrId;
      // other stuff
  }
  public class Employees: Collection<Employee>
  {
      public Employee this[EmployeeId employeeId]
      {
          get
             {
                foreach (Employee emp in this)
                   if (emp.EmployeeId == employeeId.val)
                      return emp;
                return null;
             }
      }
      public Employee this[HRId hrId]
      {
          get
             {
                foreach (Employee emp in this)
                   if (emp.HRId == hrId.val)
                      return emp;
                return null;
             }
      }
      // (or using new C#6+ "expression-body" syntax)
      public Employee this[EmployeeId empId] => 
             this.FirstorDefault(e=>e.EmployeeId == empId .val;
      public Employee this[HRId hrId] => 
             this.FirstorDefault(e=>e.EmployeeId == hrId.val;

  }

тогда, чтобы назвать его, вам придется написать:

Employee Bob = MyEmployeeCollection[new EmployeeID(34)];

и если вы написали неявный оператор преобразования:

public static implicit operator EmployeeID(int x)
{ return new EmployeeID(x); }

тогда вам даже не придется делать это, чтобы использовать его, вы можете просто написать:

Employee Bob = MyEmployeeCollection[34];

то же самое относится, даже если два индексатора возвращают разные типы...


Если вы пытаетесь сделать что-то вроде этого:

var myClass = new MyClass();

Console.WriteLine(myClass.Foos[0]);
Console.WriteLine(myClass.Bars[0]);

затем вам нужно определить индексаторы в классах Foo и Bar, т. е. поместить все объекты Foo внутри Foos и сделать foos экземпляром типа, который поддерживает индексирование напрямую.

чтобы продемонстрировать использование массивов для свойств членов (поскольку они уже поддерживают индексаторы):

public class C {
    private string[] foos = new string[] { "foo1", "foo2", "foo3" };
    private string[] bars = new string[] { "bar1", "bar2", "bar3" };
    public string[] Foos { get { return foos; } }
    public string[] Bars { get { return bars; } }
}

позволит вам сказать:

 C myThing = new C();
 Console.WriteLine(myThing.Foos[1]);
 Console.WriteLine(myThing.Bars[2]);

C# не имеет перегрузки возвращаемого типа. Можно определить несколько индексаторов, если их входные параметры различны.


нет, вы не можете сделать это. Только методы, сигнатуры которых могут отличаться только по типу возвращаемого значения, являются операторами преобразования. Индексаторы должны иметь разные типы входных параметров для компиляции.