Доступ к свойству производного класса от базового класса в C#

Ниже приведено описание BigQuery Standard SQL

#standardSQL
WITH t AS (
  SELECT "1234" AS row_id, '{ "id" : "123" , "items" : [ { "quantity" : 1 , "product" : { "id" : "p1" , "categories" : [ "cat1","cat2","cat3"]  }}] }' AS parts 
)
SELECT row_id, REPLACE(_categories, '"', '') _categories
FROM t, UNNEST(SPLIT(REGEXP_EXTRACT(
  JSON_EXTRACT(parts, '$.items'), 
  r'"categories":\[(.+?)]'))
) _categories 

, которое дает ожидаемый результат

Row row_id  _categories  
1   1234    cat1     
2   1234    cat2     
3   1234    cat3      

Обновление

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

#standardSQL
WITH t AS (
  SELECT "1234" AS row_id, '''{ "id" : "123" , "items" : [ 
      { "quantity" : 1 , "product" : { "id" : "p1" , "categories" : [ "cat1","cat2","cat3"]  }},
      { "quantity" : 2 , "product" : { "id" : "p2" , "categories" : [ "cat4","cat5","cat6"]  }}
    ] }''' AS parts 
)
SELECT row_id, REPLACE(category, '"', '') category
FROM t, UNNEST(REGEXP_EXTRACT_ALL(parts, r'"categories" : \[(.+?)]')) categories,
UNNEST(SPLIT(categories)) category  

с результатом

Row row_id  category     
1   1234    cat1     
2   1234    cat2     
3   1234    cat3     
4   1234    cat4     
5   1234    cat5     
6   1234    cat6     
9
задан Seymour 24 November 2015 в 20:32
поделиться

7 ответов

Конечно, Вы можете удрученный, как так:

for (int i = 0; i < MyList.Count; i++)
{
    if (MyList[i] is ClassA)
    {
        var a = ((ClassA)MyList[i]).PropertyA;
        // do stuff with a
    }

    if (MyList[i] is ClassB)
    {
        var b = ((ClassB)MyList[i]).PropertyB;
        // do stuff with b
    }
}

... Однако необходимо бросить другой взгляд на то, что Вы пытаетесь выполнить. Если у Вас есть общий код, который должен добраться до свойств ClassA и ClassB, то можно быть более обеспеченным доступом обертывания к тем свойствам в общее, виртуальное свойство или метод в классе предка.

Что-то как:

public class BaseClass
{
    public virtual void DoStuff() { }
}

public class ClassA : BaseClass
{
    public object PropertyA { get; set; }

    public override void DoStuff() 
    {
        // do stuff with PropertyA 
    }
}

public class ClassB : BaseClass
{
    public object PropertyB { get; set; }

    public override void DoStuff() 
    {
        // do stuff with PropertyB
    }
}
19
ответ дан 4 December 2019 в 07:49
поделиться

В дополнение к ответу TimJ можно записать один дополнительный метод, который будет работать на все типы:

public static IEnumerable<T> OfType<T>(this IEnumerable list)
{
    foreach (var obj in list)
    {
        if (obj is T)
            yield return (T)obj;
    }
}

Или если у Вас есть Linq, та функция находится в Системе пространства имен. Linq.

5
ответ дан 4 December 2019 в 07:49
поделиться
   BaseClass o = MyList[i];
   if (o is ClassB)
   {
      object k = ((ClassB)o).PropertyB;
   }
   if (o is ClassA))
   {
      object j = ((ClassA)o).PropertyA;
   }
1
ответ дан 4 December 2019 в 07:49
поделиться

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

  public static class MyBaseListExtensions
  {
    public static IEnumerable<ClassA> GetAllAs(this List<MyBaseClass> list)
    {
      foreach (var obj in list)
      {
        if (obj is ClassA)
        {
          yield return (ClassA)obj;
        }
      }
    }

    public static IEnumerable<ClassB> GetAllbs(this List<MyBaseClass> list)
    {
      foreach (var obj in list)
      {
        if (obj is ClassB)
        {
          yield return (ClassB)obj;
        }
      }
    }
  }

Затем Вы могли использовать его как....

private void button1_Click(object sender, EventArgs e)
{
  ClassA a1 = new ClassA() { PropertyA = "Tim" };
  ClassA a2 = new ClassA() { PropertyA = "Pip" };
  ClassB b1 = new ClassB() { PropertyB = "Alex" };
  ClassB b2 = new ClassB() { PropertyB = "Rachel" };

  List<MyBaseClass> list = new List<MyBaseClass>();
  list.Add(a1);
  list.Add(a2);
  list.Add(b1);
  list.Add(b2);

  foreach (var a in list.GetAllAs())
  {
    listBox1.Items.Add(a.PropertyA);
  }

  foreach (var b in list.GetAllbs())
  {
    listBox2.Items.Add(b.PropertyB);
  }
}
2
ответ дан 4 December 2019 в 07:49
поделиться

Целая предпосылка не имеет смысла - чем PropertyB был бы для экземпляр?

Можно сделать это, если Вы делаете ручную проверку типа выполнения (inst, Foo), и затем бросок к типу со свойством, которое Вы хотите.

1
ответ дан 4 December 2019 в 07:49
поделиться

Вы должны были бы иметь свойства быть объявленными как виртуальные на базовом классе и затем переопределить их в производном классе.

Исключая:

public class ClassA : BaseClass
{
   public override object PropertyA { get; set; }
}

public class ClassB: BaseClass
{
    public override object PropertyB { get; set; }
}

public class BaseClass
{
    public virtual object PropertyA { get; set; }
    public virtual object PropertyB { get; set; }
}

public void Main
{
    List<BaseClass> MyList = new List<BaseClass>();
    ClassA a = new ClassA();
    ClassB b = new ClassB();

    MyList.Add(a);
    MyList.Add(b);

    for(int i = 0; i < MyList.Count; i++)
    {
     // Do something here with the Property
        MyList[i].PropertyA;
        MyList[i].PropertyB;      
    }
}

Необходимо было бы или реализовать свойство в базовом классе, чтобы возвратить значение по умолчанию (такое как пустой указатель) или сделать это кратким обзором и вынудить все производные классы реализовать оба свойства.

Необходимо также отметить, что Вы могли возвратиться, разные вещи для говорят что PropertyA overrideing это в обоих производных классах и возвращении различных значений.

0
ответ дан 4 December 2019 в 07:49
поделиться

У Вас могли бы быть некоторые проблемы с Дженериками и подклассами (в этом случае, необходимо вернуться к Системе. Наборы. ArrayList), но необходимо бросить BaseClass к подклассу, который Вы хотите использовать. Если Вы будете использовать 'в качестве' каталога, то он успешно выполнится, если BaseClass может быть литым к подклассу, или это будет пустым, если он не может быть брошен. Это посмотрело бы что-то как:

for(int i = 0; i < MyList.Count; i++)
{
    BaseClass bc = MyList[i];
    ClassA a = bc as ClassA;
    ClassB b = bc as ClassB;
    bc.BaseClassMethod();
    if (a != null) {
       a.PropertyA;
    }
    if (b != null) {
       b.PropertyB;
    }
}

Кроме того, я должен упомянуть, что это немного плохо пахнет. Это - вид кода, который указывает на плохо структурированную объектную иерархию. В целом, если Вы не можете сказать, что BaseClass, Ваш дизайн является, вероятно, неправильным. Но, надежда, которая помогает!

0
ответ дан 4 December 2019 в 07:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: