СОЛО на клавиатуре

четверг, июня 01, 2006

Интересная штука- индексируемые свойства С# и Pascal(Delphi)

Прикольная штука Вопрос как в C# сделать код который может реализовать вот это
program IndexerTest;

{$APPTYPE CONSOLE}

{%TogetherDiagram 'ModelSupport_IndexerTest\default.txaPackage'}
{%TogetherDiagram 'ModelSupport_IndexerTest\IndexerTest\default.txaPackage'}
{%TogetherDiagram 'ModelSupport_IndexerTest\default.txvpck'}
{%TogetherDiagram 'ModelSupport_IndexerTest\IndexerTest\default.txvpck'}

uses
  SysUtils;

type
  TTestIndexer = class
  strict private
    procedure SetProperty1(i:integer;val : Integer);
    function GetProperty1(i:integer) : Integer;
    procedure SetProperty2(i:integer;val : Integer);
    function GetProperty2(i:integer) : Integer;

  private
    ar: array of integer;
  public
    constructor Create;
    property Property1 [i :integer]: Integer read GetProperty1 write SetProperty1;
    property Property2 [i :integer]: Integer read GetProperty2 write SetProperty2;
  end;
var
  ///<directed>True</directed>
IndTestArr: array[0..2] of TTestIndexer;
  i,j:integer;
constructor TTestIndexer.Create;
var
i:integer;
begin
  inherited;
  SetLength(ar,3);
  for i := 0 to 2 do
     ar[i] := i;
end;

function TTestIndexer.GetProperty1(i:integer): Integer;
begin
result := ar[i];
end;
procedure TTestIndexer.SetProperty1(i:integer;val : Integer);
begin
ar[i]:= val;
end;
function TTestIndexer.GetProperty2(i:integer): Integer;
begin
result := ar[i];
end;
procedure TTestIndexer.SetProperty2(i:integer;val : Integer);
begin
ar[i]:= val;
end;

begin
  { TODO -oUser -cConsole Main : Insert code here }
  for I := 0 to 2 do
  begin
    IndTestArr[i] := TTestIndexer.Create;
    IndTestArr[i].Property1[2] := 2;
  end;
  for I := 0 to 2 do
  begin
    for j := 0 to 2 - 1 do
    with IndTestArr[i] do
      Write(Property1[j],'  ',Property2[j]);
    Writeln;
  end;
  readln;
end.
Что тут интересно так это то что на C# влоб задачу не решить.
Нужно исхитриться
Такой код не пройдет
class testind
     {

        int [] ar;
        public testind ()
        {
           ar = new int[3];
           ar[0] = 1;
           ar[1] = 2;
           ar[2] = 3;
        }
      void setP1( int i, int val)
      {
          ar[i] = val;
      }
      int getP1( int i)
      {
       return ar[i];
      }
       public int this[int i]
          {
           get{ return ar[i];}
           set{ ar[i] = value;}
          }
      public int this[int i]
      {
          get{ return this.getP1(i);}
          set{ return this.setP1(i,value);}
      }
     }
А такой пройдет
     class testind: IMyProp1,IMyProp2
     {
       int IMyProp1.this[int i]
       {
        get{ return ar[i];}
        set{ ar[i] = value;}
       }

       int IMyProp2.this[int i]
       {
        get{ return ar[i];}
        set{ ar[i] = value;}
       }
     public IMyProp1 MyProp1{ get {return this;}}
     public IMyProp2 MyProp2{ get {return this;}}

        int [] ar;
        public testind ()
        {
           ar = new int[3];
           ar[0] = 1;
           ar[1] = 2;
           ar[2] = 3;
        }
     }

Только использовать придется таким способом – через указатель на интерфейс
MpTd.MyProp1[1] = 10;
MpTd.MyProp1[3] = 10;

1 комментарий:

Анонимный комментирует...

Приветик.

Согласно спецификации языка "The signature of an indexer consists of the number and types of its formal parameters", соответственно способа объявить два идентичных по формальным параметрам индексера в одном классе нет :)

Но вот в чем дело, в C# индексер используется для доступа к объекту через индекс, то есть доступ ведется без указания имени свойства: ti[0], подразумевается что идет обращение к индексеру, принимающему аргумент типа int. В Дельфи ты явно указываешь имя свойства, к которому ведется обращение (я не знаток Дельфи, поэтому не знаю принципиально ли это), именно поэтому становится возможным задание двух свойств. Конечно, можно написать универсальный индексер, принимающий два аргумента, а не один, реализация на скорую руку ниже.

Но мне стало интересно, если можно приведи не абстрактный пример использования именно такого механизма: два индексных свойства с одинаковой сигнатурой, возвращающих разный результат.
Мне в голову не приходит где это может пригодится... а вот небольшое неудобство с постоянным указанием имени вместо [] в глаза бросается... :)

С уважением,
Николай Мартыщенко

using System;
using System.Collections.Generic;
using System.Text;

namespace IndexerTest
{
public class TestIndexer
{
private List< int > ar;

public enum IndexTypes
{
FirstProperty,
SecondProperty
}

public int this[IndexTypes it, int index]
{
get {
switch (it)
{
case IndexTypes.FirstProperty:
return ar[index];

case IndexTypes.SecondProperty:
return ar[index];

default: throw new Exception("Unknown index type");
}
}
set
{
switch (it)
{
case IndexTypes.FirstProperty:
ar[index] = value;
break;

case IndexTypes.SecondProperty:
ar[index] = value;
break;

default: throw new Exception("Unknown index type");
}
}
}

public TestIndexer()
{
ar = new List< int >(3);
for (int i = 0; i < 2; i++)
{
ar[i] = i;
}
}
}

class Program
{
static void Main(string[] args)
{
TestIndexer ti = new TestIndexer();

Console.WriteLine(ti[TestIndexer.IndexTypes.FirstProperty,0]);
ti[TestIndexer.IndexTypes.SecondProperty, 0] = 1;
}
}
}