1

I'm looking for a way to treat ALL .Net datatypes consistently so I can create the pattern below where any type implementing IGetValue<out T> will cast to IGetValue<object>. For some reason, if T is a struct, it doesn't work and I don't understand why. Is there a way I can implement the following pattern??

public interface IGetValue<out T>
{
    T Value
    {
        get;
    }
}

public class GetValue<T> : IGetValue<T>
{
    public GetValue(T value)
    {
        _value = value;
    }

    private T _value;
    public T Value
    {
        get { return _value; }
    }
}


class Program
{
    static void Main(string[] args)
    {
        IGetValue<string> GetString = new GetValue<string>("Hello");
        IGetValue<int> GetInt = new GetValue<int>(21);

        //This works!!!
        if (GetString is IGetValue<object>)
        {
            Console.WriteLine("GetValue<string> is an IGetValue<object>");
        }
        else
        {
            Console.WriteLine("GetValue<string> is not an IGetValue<object>");
        }

        //This doesn't work!!! Why????
        if (GetInt is IGetValue<object>)
        {
            Console.WriteLine("GetValue<int> is an IGetValue<object>");
        }
        else
        {
            Console.WriteLine("GetValue<int> is not an IGetValue<object>");
        }

        Console.ReadKey();
    }
}

Edit:

I realize what I'm trying to accomplish here seems vague, but this is part of a larger design whose explanation would be too verbose. What I need is to have all of my IGetValue<T>s to share a common type or interface with a property named "Value" that returns an object. Why is the verbose part.

1
  • Value of object is very basic concept. What are you trying to accomplish here ? Commented Apr 16, 2011 at 10:41

2 Answers 2

8

It doesn't work because generic variance doesn't apply to value types... they have different representations, whereas variance with reference types can happen without the CLR having to perform any conversions.

So for example, you can treat an IEnumerable<string> as an IEnumerable<object>, but you can't treat an IEnumerable<int> as an IEnumerable<object>.

Sign up to request clarification or add additional context in comments.

8 Comments

Ok, thank you for the explanation, but is there a way to implement the pattern above.
@Verax: Not as written, no. A Foo<int> will never be a Foo<object>. It's hard to tell exactly what you're trying to do though.
I'm sorry for the vagueness. This is a part of a larger design (as you are probably aware) and I would have to explain the larger design for anyone to fully understand my goal. But that would be too verbose for this forum. Please just answer me this. int inherits from object (eventually), yes? object is a reference type, yes? So why does int need to be boxed to be a reference type if it inherits from a reference type in the first place?
"int inherits from object (eventually), yes?". Well yes and no. In your context I'd say more no than yes. Look here Jon Skeet's answer stackoverflow.com/questions/1793357/…
@Verax: Because it's not a reference type. How much do you understand about the difference between value types and reference types? I suggest you look into that before trying to understand the complexities of generic variance etc.
|
0

I ended up solving my immediate need by creating a non-generic IGetValue interface and implementing it explicitly in the class. Here's the solution:

public interface IGetValue
{
    object Value
    {
        get;
    }
}

public interface IGetValue<out T>
{
    T Value
    {
        get;
    }
}

public class GetValue<T> : IGetValue<T>, IGetValue
{
    public GetValue(T value)
    {
        _value = value;
    }

    private T _value;
    public T Value
    {
        get { return _value; }
    }

    object IGetValue.Value
    {
        get { return _value; }
    }
}


class Program
{
    static void Main(string[] args)
    {
        IGetValue<string> GetString = new GetValue<string>("Hello");
        IGetValue<int> GetInt = new GetValue<int>(21);

        if (GetString is IGetValue)
        {
            Console.WriteLine("GetValue<string> is an IGetValue");
        }
        else
        {
            Console.WriteLine("GetValue<string> is not an IGetValue");
        }


        if (GetInt is IGetValue)
        {
            Console.WriteLine("GetValue<int> is an IGetValue");
        }
        else
        {
            Console.WriteLine("GetValue<int> is not an IGetValue");
        }

        Console.ReadKey();
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.