问题
I am trying to utilize nested parameter types which appears to be illegal. I would prefer to keep the recursive function below intact so that I do not have to duplicate logic. However my nested use of <Ttype>
is making the CLR very upset (See Error listed in Code). The logic within MyMethod unavoidably creates delegates of both types Action<ClassA>
and Action<ClassB>
. Is there a way to alter the code below to accomplish my goal? Also what are the general restrictions concerning the use of type parameters (ie <Ttype>
)? Perhaps the loss of type safety is why this type of code is prohibited?
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"
}
Thanks, aidesigner
回答1:
The where clause you are using doesn't make sense. If you know the function takes ClassB, why would you not say myMethod<ClassB>(Action<ClassB> actionDelegate) ?
If you want to use some generic Ttype, you would need to say where Ttype : new() and then say new Ttype() when you call actionDelagate. That should do what you want.
public void MyMethod<Ttype>(Action<Ttype> actionDelagate) where Ttype : new()
{
MyMethod<Ttype>(v => doStuff)
actionDelagate(new Ttype()) // Expecting type "Ttype"
}
回答2:
I realized my attempt to abstract the problem made it hard to understand my restrictions. Below is the example again which is close to the implementation. The notes below should help, so you don't have to dig into the .NET classes.
- Srgs* are .NET classes in namespace "System.Speech.Recognition.SrgsGrammar"
- SrgsElement derives from SrgsItem
- C# does not support "generics variance"! This means, counter to your intuition, the recursive calls cannot pass in "Action" even though SrgsItem "is a" SrgsElement.
I was able to solve my problem by creating a CreateSrgsNodes overload with Arg1 being Action. However this means maintaining the same code in both places which fails the smell test. If someone can improve upon this please proved a new answer.
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
}
}
}
来源:https://stackoverflow.com/questions/6930340/the-use-of-nested-type-parameters-and-recursion-c