Использование параметров вложенного типа и рекурсии (C #) - PullRequest
1 голос
/ 03 августа 2011

Я пытаюсь использовать вложенные типы параметров, которые кажутся недопустимыми.Я бы предпочел оставить рекурсивную функцию ниже, чтобы не дублировать логику.Однако мое вложенное использование <Ttype> делает CLR очень расстроенным (см. «Ошибка в списке в коде»).Логика в MyMethod неизбежно создает делегатов обоих типов Action<ClassA> и Action<ClassB>.Есть ли способ изменить код ниже для достижения моей цели?Кроме того, каковы общие ограничения, касающиеся использования параметров типа (например, <Ttype>)?Возможно, потеря безопасности типа является причиной того, что этот тип кода запрещен?

ClassA-> ClassB (inherets)

public void MyMethod<Ttype>(Action<Ttype> actionDelagate) where Ttype : ClassB
{
  // Recursive Call with Ttype=ClassA
  if (Only able create Class A delagate)
     MyMethod<ClassA>(v => doStuff)

  // Recursive Call with Ttype=ClassB
  if (Only able create Class B delagate)
     MyMethod<ClassB>(v => doStuff)

  // Utilize Delagate
  if (TypeOf(Ttype) == ClassA)
    actionDelagate(new Class A) // Expecting type "Ttype"
  else
    actionDelagate(new Class B) // Expecting type "Ttype"
}

Спасибо, aidesigner

Ответы [ 2 ]

1 голос
/ 06 августа 2011

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

  • Srgs * - это классы .NET в пространстве имен "System.Speech.Recognition.SrgsGrammar"
  • SrgsElement является производным от SrgsItem
  • C # не поддерживает " универсальное отклонение "!Это означает, что, вопреки вашей интуиции, рекурсивные вызовы не могут перейти в «Action», даже если SrgsItem »является« SrgsElement.

Я смог решить свою проблему, создав перегрузку CreateSrgsNodes с Arg1,Действие.Однако это означает сохранение одного и того же кода в обоих местах, который не проходит тест на запах.Если кто-то может улучшить это, пожалуйста, подтвердите новый ответ.

    public void CreateSrgsNodes(Action<SrgsElement> addSrgsChild, CurrentNode)
    {
        foreach (GmlModel gmlModel in gmlModels)
        {

            if (<Pseudo Code: Is CurrentNode of type SrgsItem>)
            {
                var srgsOneOf = new SrgsOneOf();
                addSrgsChild(srgsOneOf);

                //Note: Arg1 is type SrgsElement
                CreateSrgsNodes(srgsOneOf.Add, CurrenNode.getChild);
            }


            if (<Pseudo Code: Is CurrentNode of type SrgsOneOf>)
            {
                var srgsOneOf = new SrgsOneOf();
                addSrgsChild(srgsOneOf);

                //Note: Arg1 is type SrgsItem (FAILS without an overload)
                CreateSrgsNodes(Action<SrgsItem>, CurrentNode))
                CreateSrgsNodes(srgsOneOf.Add,CurrenNode.getChild); created
            }
        }
    }
1 голос
/ 03 августа 2011

Предложение where, которое вы используете, не имеет смысла.Если вы знаете, что функция принимает ClassB, почему бы вам не сказать myMethod (Action actionDelegate)?

Если вы хотите использовать какой-то универсальный Ttype, вам нужно будет указать где Ttype: new (), а затем произнесите новый Ttype () при вызове actionDelagate.Это должно делать то, что вы хотите.

public void MyMethod<Ttype>(Action<Ttype> actionDelagate) where Ttype : new()
{
    MyMethod<Ttype>(v => doStuff)

    actionDelagate(new Ttype()) // Expecting type "Ttype"
}
...