Pergunta

Consider the following structure in C#:

interface I1
interface I2

abstract class A
- class A1 : A
  - class A11 : A1, I1
  - class A12 : A1, I2
- class A2 : A
  - class A21 : A2, I1
  - class A22 : A2, I2

Now I have a class B which takes an argument in the constructor. That argument must be a class that is somehow derived from A and implements the interface I2, i.e. it can be a class of type A12 or A22, but not A11 or A21. How can I define that parameter? Furthermore, I want to store the parameter later as a property in B (for later usage).

I cannot redefine A as an interface because it provides a lot of virtual methods. Neither can I skip the tree-like inheritance scheme, because A1 and A2 provide a number of specific methods that are used elsewhere (not in B). So, all I need to handle in B is stuff from A and I2.

Foi útil?

Solução

How can I define that parameter?

You can't, basically. Not in a constructor.

The closest you could come to would be to create a static generic method returning a B:

public static B CreateInstance<T>(T item) where T : A, I2

You can't do this in a constructor because constructors can't be generic.

However, then if you need to store that value, you would need to choose to have a field of type A or I2, and cast when you need to.

Of course, you could make B generic as per Enigmativity's answer - but that may have other implications elsewhere. If you want a non-generic B, you could potentially have both:

public abstract class B
{
    // Common operations which don't depend on the constructor parameter
}

public class B<T> : B where T : A, I2
{
    public B(T item)
    {
    }
}

This starts to get pretty complex, of course.

Alternatively, you could skip compile-time checking, and just check at execution time:

public class B
{
    private readonly A item;

    public B(A item)
    {
        if (!(item is I2))
        {
            throw new ArgumentException("...");
        }
        this.item = item;
    }
}

While compile-time safety is preferable in general, it may be that it's not worth the extra hoops you need to go through in this case. It really depends on what you're doing with the type.

Outras dicas

Does this work for you?

class B<T> where T : A, I2
{
    public B(T parameter)
    {
        this.Property = parameter;
    }

    public T Property { get; private set; }
}

Do you need to create instance of A1, A2, A12, A22 classes, if not then you can make them abstract and restrict the constructor parameter for only classes that implement them

class B
    {
        public B(A11 a12)
        {

        }

        public B(A22 a12)
        {

        }   

    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top