Nelrum
Nelrum

Reputation: 113

Why can't I set both XmlAttribute and XmlElement as generic constraint?

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

Answers (4)

Robert Rouhani
Robert Rouhani

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

Sergey Kalinichenko
Sergey Kalinichenko

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

O. R. Mapper
O. R. Mapper

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

Magnus Grindal Bakken
Magnus Grindal Bakken

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

Related Questions