C# Return generic abstract class - c#

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>.

Related

Return instance of deriving class from abstract generic method

What I want to do here is a bit hard to describe. My current needs require that I have an enum type that can implement an interface. While not the prettiest solution, this is what I came up with;
public class EnumClass<T> where T : Enum
{
public T Value { get; }
public string Name { get; }
public EnumClass(T enumValue)
{
Value = enumValue;
Name = Enum.GetName(typeof(T), enumValue);
}
public static EnumClass<T> Parse(string name)
{
return new EnumClass<T>((T)Enum.Parse(typeof(T), name));
}
}
Here is an example implementation:
public class AnimalTypes : EnumClass<AnimalTypesEnum>, IMyEnumInterface
{
public AnimalTypes (AnimalTypesEnum value) : base(value) { }
}
public enum AnimalTypesEnum
{
[Description("Cat")]
CAT,
[Description("Dog")]
DOG,
[Description("Horse")]
HORSE,
[Description("Bear")]
BEAR
}
When I call Parse statically on an inheritor, I have to manually cast the result back to the inheritor type from the base type, since Parse returns a generic EnumClass<T> object.
ex.
AnimalTypes dog = (AnimalTypes)AnimalTypes.Parse("DOG");
My question essentially is, is there any way to write Parse such that it returns the type of the inheritor, and not the base class? I'd also like to be able to mark EnumClass<T> abstract, but if I try doing so now, the compiler will not compile Parse, stating that I cannot create an abstract instance of type EnumClass<T> with which to return.
You can use a curiously recursive template pattern, but it requires default constructors and feels odd. Normally if things get this convoluted it's worth asking if your requirements can be restructured so that it's not so complicated, but it's hard to know if that's possible with the details given. That said, this may be as close to what you are asking for that you can get.
There isn't a way to specify that a method return the derived type, but you can specify the return type using a generic type. Below is the EnumClass, but modified to take two generic types. The first type is the enum type like before, but the second is for specifying the derived type (hence the recursive part of the template).
public abstract class EnumClass<T, TDerived>
where T : Enum where TDerived : EnumClass<T, TDerived>, new()
{
protected EnumClass()
{
}
protected EnumClass(T enumValue)
{
Value = enumValue;
}
private T _value = default(T);
public T Value
{
get => _value;
init => _value = value;
}
private string _name = null;
public string Name
{
get
{
_name = _name ?? Enum.GetName(typeof(T), Value);
return _name;
}
}
public static TDerived Parse(string name)
{
var enumValue = (T)Enum.Parse(typeof(T), name);
return new TDerived() {Value = enumValue};
}
}
Then, a derived type using this EnumClass would look like this, where the second generic type recursively refers to itself, which means that the static Parse method in the EnumClass will return a type AnimalTypes.
public class AnimalTypes : EnumClass<AnimalTypesEnum, AnimalTypes>
{
public AnimalTypes(): base()
{
}
public AnimalTypes(AnimalTypesEnum value): base(value)
{
}
}
In use, it would look like this
//because we are required to have public default constructors, it's possible
//to have a "default" AnimalTypes class that would be similar to constructing
//a "new AnimalTypes(default(AnimalTypesEnum));"
var defaultType = new AnimalTypes();
//this will output "CAT, CAT"
Console.WriteLine($"{defaultType.Value}, {defaultType.Name}");
//Since we are using init, you can initialize the value using this format
//instead of using the constructor
var horseType = new AnimalTypes() {Value = AnimalTypesEnum.HORSE};
//this will output "HORSE, HORSE"
Console.WriteLine($"{horseType.Value}, {horseType.Name}");
//normal constructor
var dogType = new AnimalTypes(AnimalTypesEnum.DOG);
//this will output "DOG, DOG"
Console.WriteLine($"{dogType.Value}, {dogType.Name}");
//static parser will return a type of AnimalTypes
var bearType = AnimalTypes.Parse("BEAR");
//this will output "BEAR, BEAR"
Console.WriteLine($"{bearType.Value}, {bearType.Name}");
You need to add another type param, in order to parametrize the return value type of Parse and enable derived/inherited types being created.
Usage:
var bear = EnumClass<AnimalTypesEnum>.Parse<AnimalTypes>("BEAR");
//AnimalTypesEnum unchanged
//AnimalTypes unchanged
public abstract class EnumClass<TEnum> where TEnum : Enum
{
public TEnum Value { get; }
public string Name { get; }
protected EnumClass(TEnum enumValue)
{
Value = enumValue;
Name = Enum.GetName(typeof(TEnum), enumValue);
}
public static TEnumClass Parse<TEnumClass>(string name)
where TEnumClass : EnumClass<TEnum>
{
//TODO: try/catch
/* Contract: the derived class must have a public constructor
that takes 1 arg of its enum type.
Generic constraints don't support ctors with args, so we need reflection here... */
return (TEnumClass)Activator.CreateInstance(
typeof(TEnumClass), Enum.Parse(typeof(TEnum), name));
}
}

C# Generic Interface and Factory Pattern

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();
}

Generic lists: The type arguments for method cannot be inferred from the usage in lambdas

I got a problem in C#, giving me an error 'The type arguments for method cannot be inferred from the usage'. Seems that the compiler cannot determine the correct interface, if I derive a generic list from a non-generic one:
Code:
public class SpecialItem : BaseItem
{
public string Title { get; set; }
}
public class BaseItem
{
public string Name { get; set; }
}
public class GenericList<T> : NongenericBaseList, IEnumerable<T>
where T: BaseItem
{
public new T this[int index]
{
get { return _items[index] as T; }
}
public new IEnumerator<T> GetEnumerator()
{
var iter = _items.GetEnumerator();
while (iter.MoveNext())
{
yield return iter.Current as T;
}
}
}
public class NongenericBaseList : IEnumerable<BaseItem>
{
protected List<BaseItem> _items;
public BaseItem this[int index]
{
get { return _items[index]; }
}
public IEnumerator<BaseItem> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Usage:
var genericList = new GenericList<SpecialItem>();
foreach (var item in genericList) // Uses IEnmerable<SpecialItem>, OK!
{
Console.WriteLine(item.Title);
}
var l = genericList.ToList(); // ERROR!
The ForEarch gets the correct Enumerator (SpecialItem), but the lambda does not know what to use (IEnumerable<BaseItem> or IEnumerable<SpecialItem>).
What to do? How can I set IEnumerable<SpecialItem> as 'default' interface? I dont want to explicetly code the type all the time like this:
var l = genericList.ToList<SpecialItem>();
First of all: kudos for providing a self-contained example!
You cannot specify a 'default' interface for type inference. The argument type for ToList<T> cannot be resolved because it is ambiguous, the type implements both IEnumerable<BaseItem> and IEnumerable<SpecialItem>, and both versions are applicable.
Is there a possibility to remove the class NongenericBaseList completely, and use the GenericList<T>instead? That would solve your problem; you can use GenericList<BaseItem> instead of NongenericBaseList
Another option is to reverse the inheritance; make NongenericBaseList empty and deriving from GenericList<BaseItem>.
Thanks to Sriram Sakthivel, he guided me to a solution with a very small overhead. To make things clear I wanted to make sure that:
Both lists, the generic and nongeneric one must be the same object. Therefore I have to derive, not packing in a wrapper.
Both lists must support access via loops (ForEach) and lambdas / extension methods without the need to explicitly typing the class name.
They have to implement IList<T>, so T out is not an option.
In short, the following code must compile without errors:
// Generic
var genericList = new GenericList<SpecialItem>();
foreach (var item in genericList)
{
Console.WriteLine(item.Title);
}
var l = genericList.ToList();
// Nongeneric
var nongenericList = genericList as NongenericBaseList;
foreach (var item in nongenericList)
{
Console.WriteLine(item.Name);
}
var nl = nongenericList.ToList();
I came to the conclusion, that this is not possible with the upper code (correct me if that is not true!). The loops are working fine, but either the generic or the nongeneric list does not work with .ToList() or other extension methods, because the compiler cannot inferre the type.
Now I used Sriram Sakthivel tipp, implementing only IEnumerable without <T>. But that allone would make it impossible to use extension methods at all even if you explicitely write the type.
I simply added a property, casting the collection:
public class NongenericBaseList : IEnumerable // Without the T!
{
protected List<BaseItem> _items;
// The property
public IEnumerable<BaseItem> L
{
get { return this as IEnumerable<BaseItem>; }
}
public BaseItem this[int index]
{
get { return _items[index]; }
}
public IEnumerator<BaseItem> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Now I can type:
var nl = nongenericList.L.ToList();
Any better solution would be appreciated!

Generic class to create concrete class automatically

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.

C#: Declaring and using a list of generic classes with different types, how?

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 { ... }
}
}

Categories

Resources