Add Item into a generic List in C# - c#

I tried to insert an object into a generic BindingList.
But if I try to add a specific object the compiler says:
"Argument type ... is not assignable to parameter type"
private void JoinLeaveItem<T>(BindingList<T> collection)
{
if (collection.GetType().GetGenericArguments()[0] == typeof(UserInformation))
{
var tmp = new UserInformation();
collection.Add(tmp);
}
}
Please help me

You cannot have objects of two different types that does not have a common anscestor in a strongly typed list. That is: In your case you will need to different collections unless your two (or more) classes have a common base class.
Try creating overloads instead, like this
private void JoinLeaveItem(BindingList<UserInformation> collection)
{
collection.Add(new UserInformation());
}
private void JoinLeaveItem(BindingList<GroupInformation> collection)
{
collection.Add(new GroupInformation());
}
Use it like this
JoinLeaveItem(userInformationCollection)
JoinLeaveItem(groupInformationCollection)
Note: I've inlined the tmp variable.

From what you've described in your comments do you want to do something like this....
private void JoinLeaveItem<T>(BindingList<T> collection) where T: new()
{
var tmp = new T();
collection.Add(tmp);
}
EDIT
If you want to add extra Tests to limit to only the items you specify you could add a big test at the beginning
private void JoinLeaveItem<T>(BindingList<T> collection) where T: new()
{
if (typeof(T) == typeof(UserInformation) || typeof(T) == typeof(GroupInformation)
var tmp = new T();
collection.Add(tmp);
}
}
Alternatively you can make a more generic solution via use of an interface.
Define an interface
public interface ILeaveItem { }
Make UserInformation and GroupInformation inherit from it and then use
private void JoinLeaveItem<T>(BindingList<T> collection) where T: ILeaveItem, new()
{
var tmp = new T();
collection.Add(tmp);
}

Related

C# Non-Generic ISet Interface

.NET 4.0 introduced a non-generic IList which exposes the ability to add values to the List without needing to know the generic type. This is useful because it allows me to write a method such as the following:
void CreateListFromBytes(IntPtr bytes, Type outputType, out object outputObject)
{
Type elementType = outputType.GenericTypeArguments[0];
int numberOfElements = ReadHeaderBytes(bytes);
bytes += Marshal.SizeOf(typeof(int));
IList outputList = (IList) Activator.CreateInstance(outputType);
for (int i = 0; i < numberOfElements; i++)
{
object element = ReadDataBytes(bytes, elementType);
bytes += Marshal.SizeOf(elementType);
outputList.Add(element);
}
outputObject = outputList;
}
However, when I try to implement a method with a similar style for HashSet or ISet, there is not such non-generic interface I can find that exposes and Add() method.
I am wondering if such an interface exists that I may have missed. If not, I am wondering how I can go about adding elements to object I know for certain is Set (since I created it the Activator.CreateInstance())
I would end up with a couple of aux types for constructing a set:
interface ISetBuilder
{
void Add(object item);
object Build();
}
class SetBuilder<T, TSet> : ISetBuilder where TSet : ISet<T>, new()
{
private readonly TSet _set = new TSet();
public void Add(object item)
{
if (!(item is T typedItem))
{
throw new ArgumentException();
}
_set.Add(typedItem);
}
public object Build() => _set;
}
Those types then could be used like this:
var builderType = typeof(SetBuilder<,>).MakeGenericType(elementType, outputType);
var builder = (ISetBuilder) Activator.CreateInstance(builderType);
var element = CreateElement(...);
builder.Add(element);
var set = builder.Build();
And yes, this could be generalised to support lists as well. Just replace ISet<T> with ICollection<T>.
Another possible (but a bit less robust) solution is just to find and call the specific Add method of a set by using reflection.

Howto someFunction(List<acceptDifferentTypesHere> list) { /*reflection stuff*/ }

I want to generate a DataTables out of Lists.
so f.e. I got two lists
List<typeA> listA = new List<typeA>();
List<typeB> listB = new List<typeB>();
how can I get a function accepting both (or more than theese) Lists with different element type?
private void someFunction(List<acceptDifferentTypesHere> list)
{
/*elementwise reflection stuff*/
}
Any help would be nice,
Harry
private void someFunction<T>(List<T> list)
{
/*elementwise reflection stuff*/
}
Used as follows
someFunction<typeA>(listA);
someFunction<typeB>(listB);
In case you want to do more with your different types (access methods, properties).
private void someFunction<T>(List<T> list) where T : MyType, new()
{
/*elementwise reflection stuff*/
var instance = new T();
Type type = instance.GetType();
instance.MyMethod();
}
public class MyType
{
public void MyMethod()
{
}
}
you can further extend this.. (e.g. use MyType as a generalization of typeA and typeB .. etc.)

Verify the type of custom class in function

In C#,I have a public function that can pass a List parameter, with T is a custom class. The function can pass with different T class. The problem that how to verify the type of T in every case?
public static List<T> ConvertData(List<T> oldDatas)
{
//I will analyze the object T,
//but now i don't know how to verify the type of T,
//with T can change,
//example maybe T is T1 class,or T2 class..
}
Thanks for my stupid question.
this is for C#
Type gt = typeof(T);
check this for java : Get generic type of java.util.List
just do :
public static class Test<T>
where T : class, new()
{
public static List<T> ConvertData(List<T> oldDatas)
{
T instanceOfT = new T();
Type typeOfT = typeof(T); // or instanceOfT.GetType();
if(instanceOfT is string)
{
// T is a string
}
else if(instanceOfT is int)
{
// T is an int
}
// ...
}
}
But that isn't productive and break the generic concept... Explain what you're trying to do.
Do you need to make different converting depends on or just want to check for specific classes? In second case you can try to specify right types for T something like:
public static List<string> ConvertData(List<string> data)
{
return PrivateConvertData<string>(data);
}
public static List<int> ConvertData(List<int> data)
{
return PrivateConvertData<int>(data);
}
private static List<T> PrivateConvertData<T>(List<T> data)
{
// code here
}
This code will check type of T during compilation.
You can use the typeof(T) keyword or use some check (if you are expecting some types to be passed via parameters):
public static List<T> ConvertData(List<T> oldDatas)
{
foreach (var itemList in oldDatas)
{
if (itemList is LinqType)
{
var linqTypeItem = (LinqType) itemList;
Console.WriteLine(linqTypeItem.PROPERTY_YOU_NEED);
}
// or
var linqTypeItem = itemList as LinqType;
if (linqTypeItem != null)
{
Console.WriteLine(linqTypeItem.PROPERTY_YOU_NEED);
}
}
}
Also you can use the Cast() method. More information here

Same method that takes a different parameter type?

I know there are very similar questions but im not sure that any of them are exactly what i need. I have 2 methods that do exactly the same thing (so i dont need to override or anything) the only difference is the parameter and return types.
public List<List<TestResult>> BatchResultsList(List<TestResult> objectList)
{
}
public List<List<ResultLinks>> BatchResultsList(List<ResultLinks> objectList)
{
}
is there a neat way of doing this that doesnt involve duplciate code (the types are used inside the method).
public List<List<T>> BatchResultsList<T>(List<T> objectList)
{
foreach(T t in objectList)
{
// do something with T.
// note that since the type of T isn't constrained, the compiler can't
// tell what properties and methods it has, so you can't do much with it
// except add it to a collection or compare it to another object.
}
}
and if you need to limit the type of T so that you'll only process specific sorts of objects, make both TestResult and ResultLinks implement an interface, say, IResult. Then:
public interface IResult
{
void DoSomething();
}
public class TestResult : IResult { ... }
public class ResultLinks : IResult { ... }
public List<List<T>> BatchResultsList<T>(List<T> objectList) where T : IResult
{
foreach(T t in objectList)
{
t.DoSomething();
// do something with T.
// note that since the type of T is constrained to types that implement
// IResult, you can access all properties and methods defined in IResult
// on the object t here
}
}
When you call the method, you can of course omit the type parameter, since it can be inferred:
List<TestResult> objectList = new List<TestResult>();
List<List<TestResult>> list = BatchResultsList(objectList);
use generic methods
public List<List<T>> BatchResultsList<T>(List<T> objectList)
{
}
when you call it for TestResult:
BatchResultsList<TestResult>(testResultList)
for ResultLinks:
BatchResultsList<ResultLinks>(resultLinksList)
EDIT:
I presume that because it's the same code inside you 2 methods, TestResult & ResultLinks must implement a common interface, let's call it SomeInterface & a common constructor, let's choose the parameterless one:
you would declare and use the method like this:
public List<List<T>> BatchResultsList<T>(List<T> objectList)
where T:SomeInterface, new()
{
List<List<T>> toReturn = new List<List<T>>();
//to instantiate a new T:
T t = new T();
foreach (T result in objectList)
{
//use result like a SomeInterface instance
}
//...
return toReturn;
}
what about
public List<IList> BatchResultsList(List<IList> objectList)
{
}
Generic version:
public List<List<T>> BatchResultsList<T>(List<T> objectList){}

Adding generic object to generic list in C#

I have class where the relevant part looks like
class C {
void Method<T>(SomeClass<T> obj) {
list.Add(obj);
}
List<?> list = new List<?>();
}
How should I define the list so that the class compiles?
I want a list of type List<SomeClass<?>>, that is a list of objects of SomeClass where each object can have any type parameter. The Java ? construct allows this; what is the C# equivalent? If no such thing exists, is there a suitable workaround? (A List<object> would do but is terribly ugly.)
I don't think you can do this in C#... you would have to add the type parameter to the class:
class C<T> {
void Method(SomeClass<T> obj) {
list.Add(obj);
}
List<SomeClass<T>> list = new List<SomeClass<T>>();
}
The other option would be to use an interface:
class C {
void Method<T>(T obj)
where T : ISomeClass {
list.Add(obj);
}
List<ISomeClass> list = new List<ISomeClass>();
}
To do what you want, you have two options.
You can use List<object>, and handle objects. This will not be typesafe, and will have boxing/unboxing issues for value types, but it will work.
Your other option is to use a generic constraint to limit to a base class or interface, and use a List<Interface>.
Unfortunately, there is no direct equivalent in C# 3.0 as generics are invariant.
You'll be able to do something like this in a graceful manner using C# 4.0 safe co/contra-variance feature.
To workaround it, you could inherit SomeClass<T> from a nongeneric base and create a List<BaseClass> instead.
If each instance of the class should hold only one type, you could make the class itself generic and set the type parameter there.
I don't know anything about Java's ? construct, but I think the following most closely preserves your existing syntax while also matching your description.
class SomeClass<T>
{
}
class C
{
void Add<T>(SomeClass<T> item)
{
Type type = typeof(SomeClass<T>);
if (!list.ContainsKey(type))
list[type] = new List<SomeClass<T>>();
var l = (List<SomeClass<T>>)list[type];
l.Add(item);
}
public void Method<T>(SomeClass<T> obj)
{
Add(obj);
}
readonly Dictionary<Type, object> list = new Dictionary<Type, object>();
}
test it with the following:
class Program
{
static void Main(string[] args)
{
var c = new C();
var sc1 = new SomeClass<int>();
var sc2 = new SomeClass<String>();
c.Method(sc1);
c.Method(sc2);
c.Method(sc1);
c.Method(sc2);
}
}
Personally, I would do this where possible; move the generic parameter from the method, to the class.
class C<T> {
void Method(SomeClass<T> obj) {
list.Add(obj);
}
List<?> list = new List<?>();
}
If your generic list is a member, it stands to reason that the class should be constructed with this in mind. It is hard for us to suggest the best pattern without more usage context for the class.

Categories

Resources