I am trying to create a Generic interface where the parameter type of one of the methods is defined by the generic
EDIT
I've changed the question slightly after realising I have probably confused matters by specifying a type parameter in the Factory creation method. What I have is two types of API calls that I need to make to a 3rd party API. The first retrieves a record from the API using an Id that is an int. The second also retrieves a record from the API but the Id is a string (guid). I have a class for each record type (ClientEntity and InvoiceEntity) that both implement a Generic Interface where I pass in the Id type
This is the Interface in which I declare a Method with an id Parameter
public interface IGeneric<TId>
{
void ProcessEntity(TId id);
}
I implement the interface in a couple of classes, one sets the id to be an int, the other a string.
public class ClientEntity: IGeneric<int> // Record with Id that is an int
{
public void ProcessEntity(int id)
{
Console.WriteLine(id);
// call 3rd party API with int Id
}
}
public class InvoiceEntity: IGeneric<string> // Record with Id that is a string (guid)
{
public void ProcessEntity(string id)
{
Console.WriteLine(id);
// call 3rd party API with string Id
}
}
What I would like to know is how do I use this within a factory pattern?
public static class GenericFactory
{
public static IGeneric<WhatGoesHere> CreateGeneric(string recordType)
{
if (recordType == "Client")
{
return new ClientEntity();
}
if (type == "Invoice")
{
return new InvoiceEntity();
}
return null;
}
}
The objective is to use the factory to instantiate the correct class so that I can call the ProcessEntity method
EDIT
I don't want to have to pass in the Generic type to the factory method because the class that is created by the factory should handle that. When I create the object, I don't know what Id type is required, I want the factory to handle that
e.g.
var myGeneric = GenericFactory.CreateGeneric("Client");
myGeneric.ProcessEntity("guid")
or
var myGeneric = GenericFactory.CreateGeneric("Invoice");
myGeneric.ProcessEntity(1234)
I hope that makes sense
You should be able to do something like this:
public static class GenericFactory
{
public static IGeneric<T> CreateGeneric<T>()
{
if (typeof(T) == typeof(string))
{
return (IGeneric<T>) new GenericString();
}
if (typeof(T) == typeof(int))
{
return (IGeneric<T>) new GenericInt();
}
throw new InvalidOperationException();
}
}
You would use it like this:
var a = GenericFactory.CreateGeneric<string>();
var b = GenericFactory.CreateGeneric<int>();
Note that this uses a strongly-typed call rather than passing in the type name as a string (which may or may not be what you actually want).
If instead you want to pass a string for the type name, you will have to return an object because there is no way to return the actual type:
public static object CreateGeneric(string type)
{
switch (type)
{
case "string": return new GenericString();
case "int": return new GenericInt();
default: throw new InvalidOperationException("Invalid type specified.");
}
}
Obviously if you have an object you would normally have to cast it to the right type in order to use it (which requires that you know the actual type).
Alternatively, you could use reflection to determine what methods it contains, and call them that way. But then you'd still need to know the type in order to pass a parameter of the right type.
I think that what you are attempting to do here is not the right approach, which you will discover once you start trying to use it.
Hacky solution: Use dynamic
Nevertheless, there is one way you can get something close to what you want: Use dynamic as follows (assuming that you are using the object CreateGeneric(string type) factory method from above):
dynamic a = GenericFactory.CreateGeneric("string");
dynamic b = GenericFactory.CreateGeneric("int");
a.ProcessEntity("A string");
b.ProcessEntity(12345);
Be aware that dynamic uses reflection and code generation behind the scenes, which can make the initial calls relatively slow.
Also be aware that if you pass the wrong type to a method accessed via dynamic, you'll get a nasty runtime exception:
dynamic a = GenericFactory.CreateGeneric("string");
a.ProcessEntity(12345); // Wrong parameter type!
If you run that code, you get this kind of runtime exception:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: The best overloaded method match for 'ConsoleApplication1.GenericString.ProcessEntity(string)' has some invalid arguments
at CallSite.Target(Closure , CallSite , Object , Int32 )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
at ConsoleApplication1.Program.Main() in D:\Test\CS6\ConsoleApplication1\Program.cs:line 71
Usually for that Factory using some DI container (DI can be useful, for example, when GenericInt or GenericString has dependencies), but to demonstrate just Idea how you can resolve this:
void Main()
{
GenericFactory.CreateGeneric<int>();
GenericFactory.CreateGeneric<string>();
}
public static class GenericFactory
{
private static Dictionary<Type, Type> registeredTypes = new Dictionary<System.Type, System.Type>();
static GenericFactory()
{
registeredTypes.Add(typeof(int), typeof(GenericInt));
registeredTypes.Add(typeof(string), typeof(GenericString));
}
public static IGeneric<T> CreateGeneric<T>()
{
var t = typeof(T);
if (registeredTypes.ContainsKey(t) == false) throw new NotSupportedException();
var typeToCreate = registeredTypes[t];
return Activator.CreateInstance(typeToCreate, true) as IGeneric<T>;
}
}
public interface IGeneric<TId>
{
TId Id { get; set; }
void ProcessEntity(TId id);
}
public class GenericInt : IGeneric<int>
{
public int Id { get; set; }
public void ProcessEntity(int id)
{
Console.WriteLine(id);
}
}
public class GenericString : IGeneric<string>
{
public string Id { get; set; }
public void ProcessEntity(string id)
{
Console.WriteLine(id);
}
}
The answer marked correct is fine if you want to use Static class but but what if you
want to return an DI injected type instead of newing an object? I suggest the
following!
public interface IGenericFactory
{
IGeneric<T> GetGeneric<T>() where T : class;
}
public class GenericFactory: IGenericFactory
{
private readonly IGeneric<int> intGeneric;
private readonly IGeneric<string> stringGeneric;
public GenericFactory(IGeneric<int> intG, IGeneric<string> stringG)
{
intGeneric = intG;
stringG = stringG;
}
public IGeneric<T> GetGeneric<T>() where T : class
{
if (typeof(T) == typeof(IGeneric<int>))
return (IGeneric<T>)Convert.ChangeType(intGeneric, typeof(IGeneric<T>));
if (typeof(T) == typeof(IGeneric<string>))
return (IGeneric<T>)Convert.ChangeType(stringGeneric,typeof(IGeneric<T>));
else
throw new NotSupportedException();
}
}
Please note i simply injected the two expected return types for clarity in the constructor. I could have implemented the factory as a Dictionary and injected the return objects into this Dictionary. Hope it helps.
I'm thinking you don't want to have to enter the type parameter similar to the LINQ methods. However the magic behind that happens because the type parameter is used in the normal parameter definitions. For example in the ToList<string>() method you can see that TSource is used between the parenthesis.
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source);
That's how the compiler knows that you want a List<string> if you call ToList() instead of ToList<string>() when called from an IEnumerable<string>
However, I don't think you need a generic type parameter in your factory method at all. All you have to do is create a non-generic version of your TGeneric<TId>
public interface IGeneric { }
public interface IGeneric<TId> : IGeneric
{
void ProcessEntity(TId id);
}
And remove the <WhatGoesHere> from the CreateGeneric method:
public static IGeneric CreateGeneric(string recordType)
{
if (recordType == "Client")
{
return new ClientEntity();
}
if (recordType == "Invoice")
{
return new InvoiceEntity();
}
return null;
}
If the function does not know the type, make it generic.
If the children are generics of different types (<int>, <string>), return object and cast inside the same factory class (Factory<T>), It is safe by typeof.
Personally, I prefer to specify the type with generics, without using an additional parameter, eg a string.
public class Program
{
public static void Main(string[] args)
{
List<Number> something = new();
Do(something);
}
public static void Do<T>(List<T> list)
{
list.Add(Factory<T>.Create());
}
}
public abstract class Factory<T>
{
private static Object ConcreteF()
{
if (typeof(T) == typeof(Number))
return new ChildGenericNumber();
throw new Exception("");
}
public static T Create()
{
return (Factory<T>)ConcreteF()).Build();
}
protected abstract T Build();
}
Related
I have the following type hierarchy:
public interface IDocument<TItem>
{
IEnumerable<TItem> Query(string query);
string FileName { get; }
}
public abstract class Document<TDocument, TItem> : IDocument<TItem>
{
public abstract IEnumerable<TItem> Query(string query);
public string FileName { get; private set; }
protected readonly TDocument _content;
}
public class DocumentX : Document<string, int>
{
...
}
public class DocumentY : Document<string, TypeOther>
{
...
}
and so on...
And I want to create a factory method, like this:
private IEnumerable<IDocument<T>> Factory<T>()
where T : IDocument<T>
{
yield return new DocumentX();
yield return new DocumentY();
}
The goal is to have a factory method, that will return a collection with different concrete implementations, which are derived from a common interface (IDocument)
But a compiler error raise:
"Cannot implicitly convert type 'DocumentX' to 'IDocument'. An explicit conversion exists (are you missing a cast?)"
What did I miss?
This is a misuse of generics. If your method is generic, it should not decide what T is. The caller decides what T is. Right now, your Factory method is making assumptions about what T exactly is. This shows that Factory should not be generic.
What you are trying to say, is something like
Hey, caller of Factory, I'm going to return a bunch of IDocument<T>s, but you don't know what the T of each one is going to be.
That's what happens when you put both a DocumentX and a DocumentY into an IEnumerable. Imagine that I'm consuming the IEnumerable returned by Factory. I won't know what kind of document each element I get is. i.e.
foreach (IDocument<???> document in Factory()) {
??? queryResult = document.Query("some query");
}
I will have no idea what I should put in ???.
Well actually, I do have a little idea of what Query would return. If I write:
foreach (IDocument<object> document in Factory()) {
object queryResult = document.Query("some query");
}
That would work, since everything can be converted to object. So we just need to write an AnyDocument class that conforms to IDocument<object>:
public class AnyDocument : IDocument<object> {
public string FileName { get; private set; }
private Func<string, IEnumerable<object>> query;
public IEnumerable<object> Query(string query)
{
return this.query(query);
}
private AnyDocument() { }
// this is used to convert an `IDocument<T>` to an AnyDocument
public static AnyDocument FromDocument<T>(IDocument<T> document) {
var doc = new AnyDocument();
doc.FileName = document.FileName;
doc.query = s => document.Query(s).Cast<object>();
return doc;
}
}
And now you can declare Factory like this:
private IEnumerable<IDocument<object>> Factory()
{
yield return AnyDocument.FromDocument(new DocumentX());
yield return AnyDocument.FromDocument(new DocumentY());
}
This whole thing could have been a lot simpler if the T in IDocument<T> is limited to reference types, i.e. no IDocument<int> like in DocumentX. Because then you can just use generic variance:
// just add the word "out"
public interface IDocument<out TItem>
Actually, I would say you should do this regardless, because then you can directly return the document objects if T is a reference type, and use AnyDocument only if T is a value type:
private IEnumerable<IDocument<object>> Factory()
{
yield return AnyDocument.FromDocument(new DocumentX());
yield return new DocumentY(); // let's say "OtherType" is a reference type
}
Try:
private IEnumerable<IDocument<T>> Factory<T>() where T : IDocument<T>, class
{
yield return new DocumentX() as T;
yield return new DocumentY() as T;
}
By casting the DocumentX, DocumentY as T you ensure all of them are at least of type IDcoument<T>, if not the class T which implements IDocument<T>.
I am writing a static guard class/api to validate parameters sent to methods.
Code so far looks like:
public static class Guard
{
public static GuardArgument<T> Ensure<T>(T value, string argumentName)
{
return new GuardArgument<T>(value, argumentName);
}
public static T Value<T>(this GuardArgument<T> guardArgument)
{
return guardArgument.Value;
}
// Example extension method
public static GuardArgument<T> IsNotNull<T>(this GuardArgument<T> guardArgument, string errorMessage)
{
if (guardArgument.Value == null)
{
throw new ArgumentNullException(guardArgument.Name, errorMessage);
}
return guardArgument;
}
}
It can be used as so:
public void Test(IFoo foo) {
Guard.Ensure(foo, "foo").IsNotNull();
}
Circumstances now require that I need to cast to concrete types from a supplied interface. Don't ask why, I just need to!
I want to add an As extension method to GuardArgument to do this, something like:
public static GuardArgument<TOut> As<TOut, TIn>(this GuardArgument<TIn> guardArgument, Type type)
where TOut : class
{
// Check cast is OK, otherwise throw exception
return new GuardArgument<TOut>(guardArgument.Value as TOut, guardArgument.Name);
}
I don't much like the syntax though. I want to be able to use the class as follows:
Foo foo = Guard.Ensure(foo, "foo")
.As(typeof(Foo))
.IsNotNull()
.Value();
I'm not sure how to write the extension method to allow this syntax though. I realise I can use the existing fluent API as:
Foo foo = Guard.Ensure(foo as Foo, "foo")
.IsNotNull()
.Value();
but I don't like this from a readability perspective.
You can get this syntax:
Foo foo = Guard.Ensure(foo, "foo")
.As<Foo>()
.IsNotNull()
.Value();
The trick is to ditch the TIn type param. It's not used in the As() method and bloats the API when type inference can't be used due to TOut. To be able to do that without getting As() suggested on all types you have to implement a new, non-generic interface for your GuardArgument<> class:
interface IGuardArgument
{
object Value { get; }
strign Name { get; }
}
public class GuardArgument<T> : IGuardArgument
{
// Explicit implementation to hide this property from
// intellisense.
object IGuardArgument.Value { get { return Value; }
// Rest of class here, including public properties Value and Name.
}
Now you can write the As() method with only one generic param:
public static GuardArgument<TOut> As<TOut>(this IGuardArgument guardArgument)
where TOut : class
{
// Check cast is OK, otherwise throw exception
return new GuardArgument<TOut>(guardArgument.Value as TOut, guardArgument.Name);
}
Introduce an IGuardArgument interface which GuardArgument{T} implements. Then you can remove TIn from the As extension method and remove the Type parameter.
Signature:
public static GuardArgument<TOut> As(this IGuardArgument guardArgument);
Usage:
Guard.Ensure(foo, "foo").As<Foo>().IsNotNull()
Is there a way to take an interface, say:
/// <summary>
/// Interface containing operators which operate on T
/// </summary>
public interface IScalarOperators<T>
{
// Adds two T objects
IOperateScalar<T> OperatorAdd { get; }
// Subtracts two T objects
IOperateScalar<T> OperatorSubtract { get; }
// Multiplies two T objects
IOperateScalar<T> OperatorMultiply { get; }
}
// Class containing all the Scalar operators for a given T
class ScalarOperators<T> : IScalarOperators<T>
{
public IOperateScalar<T> OperatorAdd { get; private set; }
public IOperateScalar<T> OperatorSubtract { get; private set; }
public IOperateScalar<T> OperatorMultiply { get; private set; }
private ScalarOperators(IOperateScalar<T> add, IOperateScalar<T> subtract, IOperateScalar<T> multiply)
{
this.OperatorAdd = add;
this.OperatorSubtract = subtract;
this.OperatorMultiply = multiply;
}
public static ScalarOperators<bool> CreateBool()
{
return new ScalarOperators<bool>(new AddBool(), new SubtractBool(), new MultiplyBool());
}
public static ScalarOperators<int> CreateInt()
{
return new ScalarOperators<int>(new AddInt(), new SubtractInt(), new MultiplyInt());
}
// METHOD I WANT TO ADD
public static ScalarOperators<T> Create()
{
// if T == bool
// return CreateBool()
// if T == int
// return CreateInt()
// else (no definition available for T)
// return null
}
// I tried something like below, but it didn't work...
public static ScalarOperators<T> Create<T>() where T: bool
{ return CreateBool(); }
public static ScalarOperators<T> Create<T>() where T : int
{ return CreateInt(); }
public static ScalarOperators<T> Create<T>()
{ return null; }
}
Notice, I'd like a generic Create method which creates the correct set of operators, but I'm not sure how to do it.
I'd like to use it to remove the parameter from this method:
public static IMatrix<T> Add<T>(this IMatrix<T> matrix, IMatrix<T> other, IScalarOperators<T> operators)
{
JoinCells<T> joiner = new JoinCells<T>();
return joiner.Join(matrix, other, null, operators.OperatorAdd);
}
becomes
public static IMatrix<T> Add<T>(this IMatrix<T> matrix, IMatrix<T> other)
{
JoinCells<T> joiner = new JoinCells<T>();
return joiner.Join(matrix, other, null, ScalarOperators<T>.Create().OperatorAdd);
}
Thanks for any help! Mainly, I just don't want to have to pass the scalarOperator object to the extension method, I'd prefer to have a 'default' since it is unlikely that the ScalarOperators will change for any T that is defined.
i suggest making a factory of IScalarOperators instead of static class ( if your really need it to be static you could access it by static field ).
you could register them at app startup and get them by this example metod:
public IScalarOperators<T> Create<T>()
{
// check if exists in dictionary
return (ScalarOperators<T>)dict[typeof(T)];
}
dict will be of type Dictionary.
The adventage is that you could add new IScalarOperators during application grow only by creating new implementing class and registering it in factory, casting is a drawback. Also you will have better seperation of concerns and ( in my opinion ) cleaner code.
What you need to do is get the type of T.
Your Create method could be like this:
public static ScalarOperators<T> Create()
{
Type type = typeof(T);
if(type == typeof(bool))
return CreateBool()
if(type == typeof(int))
return CreateInt()
else
return null
}
There are a few things happening here that I think should be addressed. You're trying to segregate your custom operators from the types that they operate on, which is confusing, and you're trying to take the very broad concept of generics and then specialize them.
For the first one, you're always going to use the same operators for the same type (at least, you're never going to try and use bool operators on an int type). There's no reason to complicate things by having a separate class for them. For the latter, generic classes and generic methods are meant to work the same for any given T. Granted, you very well could get the typeof(T) in your static factory method and compare against that for several specific cases, and then you'll have to change that for every new T that you want to handle because of this overly complicated generic operand structure.
I would recommend creating a generic interface for your operands and then implementing a wrapper for those types instead. For example, int can be wrapped like this.
public interface IScalarOperators<T>
{
IScalarOperators<T> Add (IScalarOperators<T> rightSide);
IScalarOperators<T> Subtract (IScalarOperators<T> rightSide);
IScalarOperators<T> Multiply (IScalarOperators<T> rightSide);
T Unwrap();
}
public interface IMatrix<T> where T : IScalarOperators<T> { /* whatever */ }
public class CustomInt : IScalarOperators<CustomInt>
{
private readonly int number;
public CustomInt(int number) { this.number = number; }
public CustomInt Unwrap() { return this; }
public IScalarOperators<CustomInt> Add(IScalarOperators<CustomInt> rightSide) { return new CustomInt(number + rightSide.Unwrap().number); }
public IScalarOperators<CustomInt> Subtract(IScalarOperators<CustomInt> rightSide) { return new CustomInt(number - rightSide.Unwrap().number); }
public IScalarOperators<CustomInt> Multiply(IScalarOperators<CustomInt> rightSide) { return new CustomInt(number * rightSide.Unwrap().number); }
}
At that point, you can operate on an IMatrix<CustomInt> through the IScalarOperators<T> interface and perform any exposed operations you want. As a rough example, assuming you have an exposed accessor called array, you could say IScalarOperators<T> result = matrix.array[0, 0].Add(matrix.array[0, 1]); and get a representation back of adding the two together. You could then perform any further operations on that, and so on.
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
Having the following generic class that would contain either string, int, float, long as the type:
public class MyData<T>
{
private T _data;
public MyData (T value)
{
_data = value;
}
public T Data { get { return _data; } }
}
I am trying to get a list of MyData<T> where each item would be of different T.
I want to be able to access an item from the list and get its value as in the following code:
MyData<> myData = _myList[0]; // Could be <string>, <int>, ...
SomeMethod (myData.Data);
where SomeMethod() is declared as follows:
public void SomeMethod (string value);
public void SomeMethod (int value);
public void SomeMethod (float value);
UPDATE:
SomeMethod() is from another tier class I do not have control of and SomeMethod(object) does not exist.
However, I can't seem to find a way to make the compiler happy.
Any suggestions?
Thank you.
I think the issue that you're having is because you're trying to create a generic type, and then create a list of that generic type. You could accomplish what you're trying to do by contracting out the data types you're trying to support, say as an IData element, and then create your MyData generic with a constraint of IData. The downside to this would be that you would have to create your own data types to represent all the primitive data types you're using (string, int, float, long). It might look something like this:
public class MyData<T, C>
where T : IData<C>
{
public T Data { get; private set; }
public MyData (T value)
{
Data = value;
}
}
public interface IData<T>
{
T Data { get; set; }
void SomeMethod();
}
//you'll need one of these for each data type you wish to support
public class MyString: IData<string>
{
public MyString(String value)
{
Data = value;
}
public void SomeMethod()
{
//code here that uses _data...
Console.WriteLine(Data);
}
public string Data { get; set; }
}
and then you're implementation would be something like:
var myData = new MyData<MyString, string>(new MyString("new string"));
// Could be MyString, MyInt, ...
myData.Data.SomeMethod();
it's a little more work but you get the functionality you were going for.
UPDATE:
remove SomeMethod from your interface and just do this
SomeMethod(myData.Data.Data);
Delegates can really help simplify this, and still keep things type-safe:
public void TestMethod1()
{
Action<SomeClass, int> intInvoke = (o, data) => o.SomeMethod(data);
Action<SomeClass, string> stringInvoke = (o, data) => o.SomeMethod(data);
var list = new List<MyData>
{
new MyData<int> { Data = 10, OnTypedInvoke = intInvoke },
new MyData<string> { Data = "abc", OnTypedInvoke = stringInvoke }
};
var someClass = new SomeClass();
foreach (var item in list)
{
item.OnInvoke(someClass);
}
}
public abstract class MyData
{
public Action<SomeClass> OnInvoke;
}
public class MyData<T> : MyData
{
public T Data { get; set; }
public Action<SomeClass, T> OnTypedInvoke
{ set { OnInvoke = (o) => { value(o, Data); }; } }
}
public class SomeClass
{
public void SomeMethod(string data)
{
Console.WriteLine("string: {0}", data);
}
public void SomeMethod(int data)
{
Console.WriteLine("int: {0}", data);
}
}
Just use an ArrayList and forget the MyData<T> type.
ArrayList myStuff = getStuff();
float x = myStuff.OfType<float>().First();
SomeMethod(x);
string s = myStuff.OfType<string>().First();
SomeMethod(s);
The problem with MyData<T> is that you're expecting the compiler to check a type that is only known at runtime. Compilers check types that are known at compile time.
You can't do it the way you want.
When an instance of a generic class is initialized, it is bound to particular type. Since you want to hold objects of different types in your list, you have to create an instance bound to the least common denominator — in your case it's Object.
However, that means that Data property now will return an object of type Object. The compiler cannot infer the actual data type at compile time, so it can choose the appropriate SomeMethod overload.
You have to either provide an overload of SomeMethod that takes Object as a parameter, or remove the requirement to hold different such different types in your collection.
Or you can go with a standard IEnumerable collection (like Array) and use the OfType<> extension method to get the subset of the collection of particular type.
In that case you need MyData<object> since that is the only thing those types have in common.
You can create a generic wrapper for SomeMethod and check for the type of the generic argument, then delegate to the appropriate method.
public void SomeMethod<T>(T value)
{
Type type = typeof(T);
if (type == typeof(int))
{
SomeMethod((int) (object) value); // sadly we must box it...
}
else if (type == typeof(float))
{
SomeMethod((float) (object) value);
}
else if (type == typeof(string))
{
SomeMethod((string) (object) value);
}
else
{
throw new NotSupportedException(
"SomeMethod is not supported for objects of type " + type);
}
}
Suggested wildcards a while back here. Closed as "won't fix" :(
Generics allow you to specify one type for the whole list when you create the list, for example a list for storing int would be created like this
var myData = new MyData<int>();
If you want to store multiple types in the same generic list you can specify a common base type or interface for those types. Unfortunately in your case the only common base type for the types you want to store would be object.
var myData = new MyData<object>();
But you can just use the non-generic list for storing objects.
Inherit MyData<T> from a non-generic MyData class and make a list of that.
This way, you can't automatically resolve the overload. You have to do it manually.
abstract class MyData {
protected abstract object GetData();
protected abstract Type GetDataType();
public object Data {
get { return GetData(); }
}
public Type DataType {
get { return GetDataType(); }
}
}
class MyData<T> : MyData {
protected override object GetData() { return Data; }
protected override Type GetDataType() { return typeof(T); }
public new T Data {
get { ... }
}
}