-1

Let's say I'm working with generic function :

public interface IFoo
{
  Type Type;
  TValue Read<TValue>();
}

public class Foo : IFoo {}

var f = new Foo();

I'd like to write :

var value = f.Read<f.Type>();

but this gives error :

f is a variable but is used like a type

I could write conditionals :

object value;
if (f.Type == typeof(bool))
{
    value = f.Read<bool>();
}
if (f.Type == typeof(byte))
{
    value = f.Read<byte>();
}
...

but this doesn't really work because it's verbose , may be incomplete if I don't know in advance all possible types , and value is an object instead of the type.

Is there a solution ?

BaltoStar
  • 8,165
  • 17
  • 59
  • 91
  • No you can't do this - what would the type of `value` be? When working with runtime type information you have to do things dynamically until you can cast to a known type. In this case you can add a `object Read(Type t)` method and implement the generic version by delegating to this method. – Lee Jul 08 '17 at 18:47
  • What if you make the interface generic? – juharr Jul 08 '17 at 18:58
  • strictly speaking, you get an error because of using property where you shouls use: var value = f.Read(); / not that i understand overall intention anyways – dee zg Jul 08 '17 at 18:59
  • will you be reading one type per instance of Foo or you want to read multiple different types during single instance lifetime? – dee zg Jul 08 '17 at 19:01
  • @BaltoStar ok, so if you know the type at the moment of creating Foo instance and that type stays the same for instanve lifetime then take a look at answer from Helmut. thats your bets way to do it. – dee zg Jul 08 '17 at 20:54
  • @deezg each instance of `Foo` contains a single internal object stored as `byte[]` that is interpreted as type `TValue` ... please note that `f.Read()` gives same error `f is a variable but is used like a type` ... apparently it's an error if a variable appears anywhere inside the type specifier – BaltoStar Jul 08 '17 at 21:15

2 Answers2

2

If the type is known at the time you create the instance of Foo (and doesn't change afterwards), then a generic interface would be the best solution:

public interface IFoo<T>
{
    T Read();
}

public class Foo<T> : IFoo<T>
{
    public T Read()
    {
        Type type = typeof(T);

        byte[] buffer = ...get byte array from wherever...;
        object boxedResult;

        using (MemoryStream ms = new MemoryStream(buffer))
        {
            using (BinaryReader br = new BinaryReader(ms))
            {
                if (type == typeof(int))
                    boxedResult = br.ReadInt32();
                else if (type == typeof(long))
                    boxedResult = br.ReadInt64();
                else if (type == typeof(bool))
                    boxedResult = br.ReadBoolean();
                else if (type == typeof(byte))
                    boxedResult = br.ReadByte();

                // ...
                // other types you want to process
                // ...

                else boxedResult = null;
            }
        }
        if (boxedResult != null)
            return (T)boxedResult;
        else
            throw new Exception(string.Format("{0} not supported", type.Name));
    }
}

You use the class like this:

var intFoo = new Foo<int>();
var boolFoo = new Foo<bool>();

int intVal = intFoo.Read();
bool boolVal = boolFoo.Read();
Helmut D
  • 630
  • 6
  • 11
  • show him generic Foo definition also and creation of Foo instance – dee zg Jul 08 '17 at 20:55
  • @HelmutD type does not change per instance of `Foo` but changing to `IFoo` and `Foo` is not realistic because internally `Foo` is `byte[]` – BaltoStar Jul 08 '17 at 21:11
  • "internally Foo is byte[]": You mean, you are reading bytes and want to convert them to the generic type? Unfortunately byte[] doesn't implement the IConvertible interface, so you will have to explicitly convert the bytes to all types that the generic parameter T may take. – Helmut D Jul 09 '17 at 09:48
  • I have added a possible implementation of IFoo, using the solution proposed by Henk Holtermann in https://stackoverflow.com/questions/30201620. If you get the byte array from a stream in the first place, then you can use this directly, of couse. – Helmut D Jul 09 '17 at 10:27
1

Although there are ways to solve this problem through reflection or with LINQ expressions, I think the root cause of your problem is in the poor design of your IFoo interface.

If all you need is an object result from a read, change the interface to this:

public interface IFoo {
    Type Type {get;}
    object Read();
}

This would let you avoid using generics where its us needs to be "undone" to get an object.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • `object Read();` is useful if just i want to output `object.ToString()` but otherwise i'd have to write a messy conversion function – BaltoStar Jul 08 '17 at 21:14