简体   繁体   中英

Accessing generic object in generic list in C#

I am relatively new to C# and I would like to create a list of generic objects.

Here is how I try to do it:

I create a base class:

public class BaseClass
{
}

And I inherit a generic class from the base class:

public class GenericClass<T> : BaseClass where T: struct
{
    public T data;
    public GenericClass(T value)
    {
        data = value;
    }
    public T doSomething()
    {
        return (T)(data * (dynamic)0.826f);
    }
}

Then I can create a list of base class:

List<BaseClass> ListOfGenericClasses = new List<BaseClass>();

And I can add instances of the inherited geneic class:

ListOfGenericClasses.Add(new GenericClass<int>(100));            
ListOfGenericClasses.Add(new GenericClass<byte>(101));
ListOfGenericClasses.Add(new GenericClass<float>(10.1f));
ListOfGenericClasses.Add(new GenericClass<double>(100.10));
ListOfGenericClasses.Add(new GenericClass<ulong>(9999999999));
ListOfGenericClasses.Add(new GenericClass<long>(-9999999999));
ListOfGenericClasses.Add(new GenericClass<uint>(62389));
ListOfGenericClasses.Add(new GenericClass<sbyte>(-103));

I also can invoke each objects method:

string s = "";
s += ((GenericClass<int>)(ListOfGenericClasses[0])).doSomething() + " # ";
s += ((GenericClass<byte>)(ListOfGenericClasses[1])).doSomething() + " # ";
s += ((GenericClass<float>)(ListOfGenericClasses[2])).doSomething() + " # ";
s += ((GenericClass<double>)(ListOfGenericClasses[3])).doSomething() + " # ";
s += ((GenericClass<ulong>)(ListOfGenericClasses[4])).doSomething() + " # ";
s += ((GenericClass<long>)(ListOfGenericClasses[5])).doSomething() + " # ";
s += ((GenericClass<uint>)(ListOfGenericClasses[6])).doSomething() + " # ";
s += ((GenericClass<sbyte>)(ListOfGenericClasses[7])).doSomething();
MessageBox.Show(s);

And here comes the question: how do I get the value of each instance in the list generally?

I try to do something like this:

string s = "";
for (int i = 0; i < ListOfGenericClasses.Count; i++)
{
    s += ((GenericClass<ListOfGenericClasses[i].GetType().GetGenericArguments()[0]>)(ListOfGenericClasses[i])).dosdoSomething() + " # ";               
}
MessageBox.Show(s);

I have the following error message: "Using the generic type 'GenericClass requires 1 type argument'"

EDIT: sorry guys I could have been more precize when asking my question: my point was not to use the return value to build a string it was just for seeing the result on screen

Any help is much apreciated,

Thanks in advance

I'd approach it in a slightly different way:

public class BaseClass
{
     public virtual string DoSomethingToString() { throw new NotImplementedException(); }
}

Then you'd implement your derived class as follows:

public class GenericClass<T> : BaseClass where T: struct
{
    public T data;
    public GenericClass(T value)
    {
        data = value;
    }

    public T DoSomething()
    {
        return (T)(data * (dynamic)0.826f);
    }

    public override string DoSomethingToString()
    {
        return DoSomething().ToString();
    }
}

Now you can iterate List<BaseClass> and directly call each element's DoSomethingToString() method.

Should you use Generics? I re-wrote your app and solved the problem by removing Generics

public class GenericClass : BaseClass
{
    public object data;
    public GenericClass(object value)
    {
        this.data = value;
    }
    public object doSomething()
    {
        return (object)(this.data * (dynamic)0.826f);
    }
}

Then I did it:

for (var i = 0; i < ListOfGenericClasses.Count; i++)
{
    s += ListOfGenericClasses[i].doSomething() + " # ";
}

You would need to use reflection to get the type and then from that get the method which you can then invoke:

string s = "";
for (int i = 0; i < ListOfGenericClasses.Count; i++)
{
    s += ListOfGenericClasses[i].GetType()
                       .GetMethod("doSomething")
                       .Invoke(ListOfGenericClasses[i], null);
}

However, I would recommend you take the approach as suggested by @corak in the comments and by @InBetween in their answer and create a virtual method in BaseClass and override it in GenericClass .

First use stringBuilder to concat strings, you can cast your object to dynamic to invoke the method you need dynamically:

 var stringbuilder = new StringBuilder();

            foreach (var l in ListOfGenericClasses)
            {
                var st = (l as dynamic).doSomething() + " # ";
                stringbuilder.Append(st);
            }

    MessageBox.Show(stringbuilder.ToString());

Does this do what you want?

string s = "";
for (int i = 0; i < ListOfGenericClasses.Count; i++)
{
    Type type = ListOfGenericClasses[i].GetType();          
    dynamic d = Convert.ChangeType(ListOfGenericClasses[i], type);
    s += d.doSomething() + " # ";               
}

It looks like you are trying to implement a union type. I am sure there must be better ways than this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM