【问题标题】:C# Multiple IndexersC# 多索引器
【发布时间】:2010-09-30 16:30:37
【问题描述】:

是否有可能有类似以下的东西:

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

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

如果没有,那么我可以通过哪些方式实现这一目标?我知道我可以创建名为 getFoo(int i) 和 getBar(int i) 的函数,但我希望使用属性来做到这一点。

【问题讨论】:

    标签: c# properties indexer


    【解决方案1】:

    不是在 C# 中,不是。

    但是,您始终可以从属性中返回集合,如下所示:

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

    IList 有一个索引器,因此您可以编写以下内容:

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

    在“返回...;”行你可以返回任何实现 IList 的东西,但你可能会返回一个围绕你的集合的只读包装器,请参阅 AsReadOnly() 方法。

    【讨论】:

    • 这就是我正在寻找的解决方案。
    【解决方案2】:

    如果你想这样做:

    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]);
    

    【讨论】:

    • 问题是您不能将它们设为只读,因为它们是数组,例如myThing.Foos[1] = null;
    【解决方案3】:

    C# 没有返回类型重载。如果输入参数不同,您可以定义多个索引器。

    【讨论】:

      【解决方案4】:

      不,你不能这样做。只有其签名仅因返回类型而异的方法才是转换运算符。索引器必须具有不同的输入参数类型才能编译。

      【讨论】:

        【解决方案5】:

        有一种方法..如果您定义 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];
        

        即使两个索引器返回不同的类型,同样的事情也适用......

        【讨论】:

        • 虽然乍一看这看起来很简洁,但它不是自我解释的,而且有一点“魔力”。如果你遇到其他人写这篇文章,你会假设只有一个索引或结果,但在这种情况下,你可以根据传入的类型返回两个完全不同的结果,我知道你没有这样做,但你必须是小心。
        • 我猜任何你没有立即认出和不熟悉的东西,都有一种“神奇”的感觉,不是吗?我第一次看到 lambdas 时完全糊涂了。
        【解决方案6】:

        来自 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);  
                }
            }      
        }
        

        【讨论】:

          【解决方案7】:

          尝试我的 IndexProperty 类以在同一类中启用 multiple indexers

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

          【讨论】:

            【解决方案8】:

            我认为接受的答案是错误的。如果您将使用显式接口实现,则有可能:

            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();
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-11-09
              • 2010-11-21
              • 1970-01-01
              • 1970-01-01
              • 2016-07-16
              • 1970-01-01
              • 2019-10-24
              相关资源
              最近更新 更多