Reputation: 113
I'm trying to set XmlAttribute
and XmlElement
as allowed types for generic type but when I'm setting both of them a the same time I'm getting an error during compilation:
The class type constraint 'System.Xml.XmlElement' must come before any other constraints
Example of code:
interface TestClass<T, T2> : IEnumerable where T2: XmlAttribute, XmlElement
{
...
}
Why wouldn't it allow me to set constraints like this?
Upvotes: 0
Views: 319
Reputation: 14678
The reason you can't do this is because the two types have different members. Think about using this on a method, what would happen inside the body? How would you be able to write a method without knowing which type is being passed in? How would autocomplete react to this kind of a constraint?
Your best bet is to choose the common base class - System.Xml.XmlNode
, or perhaps create two separate interfaces, one with the XmlAttribute
, the other with the XmlElement
.
For example:
public interface ICommonInterface<T> : IEnumerable
{
//common things that rely only on the first type go here
}
public interface IAttributeInterface<T, T2> : ICommonInterface<T>
where T2 : XmlAttribute
{
}
public interface IElementInterface<T, T2> : ICommonInterface<T>
where T2 : XmlElement
{
}
If the primary goal of the interface is something that uses both types together for the most part, then you should either be using the XmlNode
constraint or wrapper classes ala Adapter/Facade pattern.
Upvotes: 0
Reputation: 726559
When you list multiple constrains separated by comma, you tell C# that T
must satisfy all* these constraints, not one or the other. You cannot make a constraint saying that T
must be one of two classes. By constraining the type parameter, you increase the number of allowable operations and method calls to those supported by the constraining type and all the interfaces that you list as the type constraints. That is the purpose of having type class-based and interface-based constraints in the first place - letting you call operations beyond what's supported by the System.Object
class.
As a result, you never put two classes in a list of constraint (but you can put a class and as many interfaces as you wish, of course). Even when the two classes are related, putting the most derived one in the constraint would be equivalent to putting both of them in.
Upvotes: 1
Reputation: 20731
The constraint you are using does not represent a list of allowed types. It means "anything inserted for T2
must inherit from ."
This is so the compiler can be sure that anything inserted for T2
provides a certain public interface - properties and methods -, namely those inherited from the specified type. If you could list more than one alternative there, which interface would be taken for granted? Depending on what would be inserted, T2
could have either all the methods and properties offered by XmlAttribute
or all the methods and properties offered by XmlElement
, but none of them for sure.
Upvotes: 3
Reputation: 2113
Keep in mind that the comma between XmlAttribute
and XmlElement
means and, not or. XmlAttribute
and XmlElement
are classes, and since C# doesn't have multiple inheritance it's impossible for any generic parameter to satisfy the constraint.
Upvotes: 0