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

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

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

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

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


person smack0007    schedule 10.01.2009    source источник


Ответы (8)


Не в С#, нет.

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

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

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

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

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

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

person Community    schedule 10.01.2009
comment
Это решение, которое я ищу. - person smack0007; 10.01.2009

Это из спецификации С# 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);  
        }
    }      
}
person Jacob_J    schedule 30.10.2009

ЕСТЬ способ... если вы определите 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];

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

person Charles Bretana    schedule 10.01.2009
comment
Хотя на первый взгляд это выглядит аккуратно, это не говорит само за себя и имеет немного волшебства. Если бы вы столкнулись с тем, что кто-то еще пишет это, вы бы предположили, что существует только один индекс или результат, но в этом случае вы можете вернуть два совершенно разных результата в зависимости от переданного типа, я знаю, что вы этого не сделали, но вы должны быть осторожный. - person rolls; 11.05.2017
comment
Я полагаю, что все, что вы не узнаете сразу и с чем незнакомы, имеет какое-то волшебное ощущение, не так ли? Когда я впервые увидел лямбды, я был совершенно сбит с толку. - person Charles Bretana; 11.05.2017

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

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

person Sion COhen    schedule 25.01.2012

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

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]);
person Dylan Beattie    schedule 10.01.2009
comment
Проблема в том, что вы не можете сделать их доступными только для чтения, поскольку они являются массивами, например. myThing.Foos[1] = ноль; - person Mike Scott; 10.01.2009

Я считаю, что принятый ответ неверен. Это возможно, если вы будете использовать явную реализацию интерфейса:

class C
{
    public IFooProvider Foos => this;
    public IBarProvider Bars => this;

    Foo IFooProvider.this[int i]
    {
        ...
    }

    Bar IBarProvider.this[int i]
    {
        ...
    }

    public interface IFooProvider
    {
        Foo this[int i] { get; set; }
    }

    public interface IBarProvider
    {
        Bar this[int i] { get; set; }
    }
}

Затем вы можете использовать его точно так, как вы хотели:

C c;
c.Foos[1] = new Foo();
c.Bars[0] = new Bar();
person Parchandri    schedule 16.04.2021

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

person JoshBerke    schedule 10.01.2009

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

person Krzysztof Kozmic    schedule 10.01.2009