Pass Type argument to Generic Class - c#

I need to pass type as an argument to a generic class. I am trying to get the type from list of types. Example:
void Main()
{
var test = new Test();
test.testMethod();
}
public static class ListClass<T>
{
public static bool getValues()
{
return true;
}
}
public class X { public int a; public int b; }
public class Y { public string s; public float f; }
class Test
{
List<Type> listType = new List<Type>();
public Test()
{
listType.Add(typeof(X));
listType.Add(typeof(Y));
}
public void testMethod()
{
Console.WriteLine(ListClass<X>.getValues());
Console.WriteLine(ListClass<Y>.getValues());
}
}
I want to loop the calls instead of calling in each line.

Let's assume, for the sake of the argument, that the code you posted in your question, as per my request in the comments, was this:
void Main()
{
var test = new Test();
test.testMethod();
}
public static class ListClass<T>
{
public static bool getValues()
{
return true;
}
}
public class X { public int a; public int b; }
public class Y { public string s; public float f; }
class Test
{
List<Type> listType = new List<Type>();
public Test()
{
listType.Add(typeof(X));
listType.Add(typeof(Y));
}
public void testMethod()
{
Console.WriteLine(ListClass<X>.getValues());
Console.WriteLine(ListClass<Y>.getValues());
}
}
That's basically code that will compile and will run. So now you want to know how to actually run this illegal code:
public void testMethod()
{
foreach (var type in listType)
{
Console.WriteLine(ListClass<type>.getValues());
}
}
Here's how:
public void testMethod()
{
foreach (var type in listType)
{
Console.WriteLine(
(bool)typeof(ListClass<>)
.MakeGenericType(type)
.GetMethod("getValues")
.Invoke(null, new object[] { }));
}
}
Now I don't know if this is the code you need because you didn't post the example that I was asking for. Nevertheless, I hope this helps.

Related

How to separate C# tuple values to match method arguments

I am wondering is it possible to 'spread' tuple's values in a way to properly match method arguments.
For example:
public (int, object) GetTuple() {
return (5, null);
}
public void ReceiveMultipleArguments(int a, object b) { ... }
The call of ReceiveMultipleArguments method like this:
ReceiveMultipleArguments(GetTuple());
will result in this error:
CS7036: There is no argument given that corresponds to the required formal parameter 'b' of 'Method1(int, object)'
The possible solution is to destructure tuple manually then provide each value as method argument, but is there a way to do it shorter, like spread operator that exists in javascript, for example?
C# is a strongly typed language, so you cannot pass tuple (which has its own class ValueTuple class).
So, you could just define overload for the method:
public void Test()
{
ReceiveMultipleArguments(GetTuple());
}
public (int, object) GetTuple()
{
return (5, null);
}
public void ReceiveMultipleArguments((int a, object b) #params) => ReceiveMultipleArguments(#params.a, #params.b);
public void ReceiveMultipleArguments(int a, object b) { ... }
You could change the signature of the method to support params of object elements. Then you could unpack the tuple into individual elements and use that as parameter.
public void Main()
{
var tuple = GetTuple();
var items = UnpackTuple(tuple).ToArray();
DoSomethingWith(items);
}
public void DoSomethingWith(params object[] data)
{
foreach (var d in data)
{
Console.WriteLine(d);
}
}
public IEnumerable<object> UnpackTuple(ITuple tuple)
{
for (var index = 0; index < tuple.Length; index++)
{
yield return tuple[index];
}
}
public ITuple GetTuple()
{
return Tuple.Create(5, "second", 2.489, 'G');
}
However, I would strongly advice you to move away from tuples if you need to move them around in your program. From experience, I have seen that this will lead to a messy code base that is hard to understand and change.
Instead, define classes for your tuples. Lets say you need to pass an object, let's say an apple, and a count for how many apples into some method. The class could be a generic class such as:
public class CountOf<T>
{
public CountOf(T value, int count)
{
this.Value = value;
this.Count = count;
}
public T Value { get; }
public int Count { get; set; }
}
Or non-generic, such as:
public class CountedObject
{
public CountedObject(object obj, int count)
{
this.Object = obj;
this.Count = count;
}
public object Object { get; }
public int Count { get; set; }
}
Use case:
public void Main()
{
var apple = new Apple();
var countedApples = new CountOf<Apple>(apple, 10);
DoSomethingWith(countedApples);
var countedObject = new CountedObject(apple, 10);
DoSomethingWith(countedObject);
}
public void DoSomethingWith(CountOf<Apple> countedApples)
{
// do something here
}
public void DoSomethingWith(CountedObject countedObject)
{
// do something here
}
public class Apple { }
public class CountOf<T>
{
public CountOf(T value, int count)
{
this.Value = value;
this.Count = count;
}
public T Value { get; }
public int Count { get; set; }
}
public class CountedObject
{
public CountedObject(object obj, int count)
{
this.Object = obj;
this.Count = count;
}
public object Object { get; }
public int Count { get; set; }
}
maybe this help you:
static void Main(string[] args)
{
ReceiveMultipleArguments(GetTuple());
Console.WriteLine();
}
public static (int, object) GetTuple()
{
return (5, null);
}
public static void ReceiveMultipleArguments((int, object) p)
{
Console.WriteLine(p.Item1);
Console.WriteLine(p.Item2);
}

Casting from concrete Type to interface

I have following code that does not compile
using System.Collections.Generic;
public interface IElement
{
}
public class AElement : IElement
{
public void DoSomethingSpecial()
{ }
}
public class Container<TElement>
{
public List<TElement> Elements { get; } = new();
}
public class Program
{
public static Container<IElement> GetContainer()
{
var concreteContainer = new Container<AElement>();
concreteContainer.Elements.ForEach(e => e.DoSomethingSpecial());
return concreteContainer; // Cannot implicitly convert type 'Container<AElement>' to 'Container<IElement>'
}
public static void Main()
{
var myContainer = GetContainer();
}
}
I read documentation about Covariance, Invariance, Contravariance and out Types.
And I am more confused than at the beginning.
Whats the way to fix this?
Code online: https://dotnetfiddle.net/85AgfT
You need to generate implicit conversion operator:
public class Container<IElement>
{
public List<IElement> Elements { get; } = new List<IElement>();
public static implicit operator Container<IElement>(Container<AElement> v)
{
//here you need to create Container<IElement> with your Container<AElement> 'v' values
return new Container<IElement>();
}
}
I finally got it working
using System.Collections.Generic;
public interface IContainer<out TElement>
{
}
public interface IElement
{
}
public class AElement : IElement
{
public void DoSomethingSpecial()
{ }
}
public class Container<TElement> : IContainer<TElement>
{
public List<TElement> Elements { get; } = new();
}
public class Program
{
public static IContainer<IElement> GetContainer()
{
var concreteContainer = new Container<AElement>();
concreteContainer.Elements.ForEach(e => e.DoSomethingSpecial());
return concreteContainer;
}
public static void Main()
{
var myContainer = GetContainer();
}
}
Make Container also an Interface and use an out Type parameter

Implement abstract method of instance on initialization

There is a way to implement an abstract method of instance on initialization in C# like in Java?
public static abstract class A
{
public abstract String GetMsg();
public void Print()
{
System.out.println(GetMsg());
}
}
public static void main(String[] args)
{
A a = new A()
{
#Override
public String GetMsg()
{
return "Hello";
}
};
a.Print();
}
No you can't - but you can achieve the same end by using a Func<string>:
using System;
namespace Demo
{
public sealed class A
{
public Func<string> GetMsg { get; }
public A(Func<string> getMsg)
{
GetMsg = getMsg;
}
public void Print()
{
Console.WriteLine(GetMsg());
}
}
public static class Program
{
public static void Main()
{
var a = new A(() => "Hello");
a.Print();
}
}
}
Alternatively, if you want to be able to change the GetMsg property after initialization:
using System;
namespace Demo
{
public sealed class A
{
public Func<string> GetMsg { get; set; } = () => "Default";
public void Print()
{
Console.WriteLine(GetMsg());
}
}
public static class Program
{
public static void Main()
{
var a = new A(){ GetMsg = () => "Hello" };
a.Print();
}
}
}
(This uses c#6 syntax - you'd have to modify it slightly for earlier versions.)

Explicit use of base method without using keyword new in child method

Due to the polymorphism property of the classes, below example will print AB twice, which is expected.
In my case, I really want it to print A then AB.
I decided to change the Get() method in B from overrides to new.
This solves my problem, but they informed me of bad practise, so I'm looking for an alternative...
The one thing that comes to mind is to instantiate a new A in B.Do(), which I think is also bad practise...
//ORIGINAL
class Program
{
static void Main(string[] args)
{
var b = new B();
b.Do();
}
}
public class A
{
public virtual void Do()
{
var get = Get();
Console.WriteLine(get);
}
public virtual string Get()
{
return "A";
}
}
public class B : A
{
public override void Do()
{
base.Do();
var get = Get();
Console.WriteLine(get);
}
public override string Get()
{
return base.Get() + "B";
}
}
//UPDATED, USING NEW
class Program
{
static void Main(string[] args)
{
var b = new B();
b.Do();
Console.ReadLine();
}
}
public class A
{
public virtual void Do()
{
var get = Get();
Console.WriteLine(get);
}
public virtual string Get()
{
return "A";
}
}
public class B : A
{
public override void Do()
{
base.Do();
var get = Get();
Console.WriteLine(get);
}
public new string Get()
{
return base.Get() + "B";
}
}
Instead of calling the base version of Do in B.Do, you can change the implementation as follows:
public class B : A
{
public override void Do()
{
// Call the base version of Get explicitly
var getBase = base.Get();
Console.WriteLine(getBase);
// Call the current implementation of Get
var get = Get();
Console.WriteLine(get);
}
public override string Get()
{
return "B";
}
}
This will technically solve your problem, but is not a really clean solution from an OOP point of view. I suggest to think a bit about whether you need to be able to override Get independently. Maybe changing the signatures of your methods so that Get always returns a list of strings that should be printed is also a good solution (I've renamed Get to GetLines to reflect the changed purpose of the method):
public class A
{
public virtual void Do()
{
var lines = GetLines();
foreach(var line in lines)
Console.WriteLine(line);
}
public virtual IEnumerable<string> GetLines()
{
return new string[] { "A" };
}
}
public class B : A
{
public override IEnumerable<string> GetLines()
{
var lst = new List<string>(base.GetLines());
lst.Add("B");
return lst;
}
}
Here is the corrected code:
class Program
{
static void Main(string[] args)
{
var b = new B();
b.Do();
}
}
public class A
{
public virtual void Do()
{
Console.WriteLine(Get());
}
public virtual string Get()
{
return "A";
}
}
public class B : A
{
public override void Do()
{
Console.WriteLine(base.Get());
base.Do();
}
public override string Get()
{
return base.Get() + "B";
}
}

Generic T to call overloaded functions

I want to do something like this:
public class Object1 {
public int number{get;set;}
}
public class Object2 {
public int number{get;set;}
}
public class Object3 {
public int number{get;set;}
}
main();
public void main(){
var objects1 = new List<Object1>{new Object1{number=1} , new Object1{number=2}};
test<Object1>(objects1);
}
public List<Object3> test<T>(IEnumerable<T> objs){
var rv = new List<Object3>();
foreach (var o in objs)
{
var foo = overloaded(o);
rv.Add(foo);
}
return rv;
}
public Object3 overloaded(Object1 obj){
// Run very specific things to Object1
return new Object3{number=obj.number+1};
}
public Object3 overloaded(Object2 obj){
// Run very specific things to Object2
return new Object3{number=obj.number+2};
}
You can directly run/edit the code here, with error handling:
http://csharppad.com/gist/6ff5f13cac8f0e5735be
The error I get is Argument 1: cannot convert from 'T' to 'Object1' - So how can I do this? The idea is that Object1 and Object2 have 95% of their code identical, it's that last 5% that I need to have it do something specific for each.
You could use dynamic to in your test method, just note that there are performance implications:
overloaded((dynamic)obj);
I would reverse your thinking.
Try this:
private void test<T>(T obj){
// Do common stuff
}
public void overloaded(Object1 obj){
test(obj);
Console.WriteLine("Do Object 1 stuff");
}
public void overloaded(Object2 obj){
test(obj);
Console.WriteLine("Do Object 2 stuff");
}
and call overloaded instead of calling test.
After playing around I was able to come up with this
public class Object1 {
public int number{get;set;}
}
public class Object2 {
public int number{get;set;}
}
public class Object3 {
public int number{get;set;}
}
main();
public void main(){
var objects1 = new List<Object1>{new Object1{number=1} , new Object1{number=2}};
test<Object1>(objects1);
}
public List<Object3> test<T>(IEnumerable<T> objs){
var rv = new List<Object3>();
foreach (var o in objs)
{
if(typeof(T) == typeof(Object1)){
rv.Add(overloaded((Object1)(object)o));
} else {
rv.Add(overloaded((Object2)(object)o));
}
}
return rv;
}
public Object3 overloaded(Object1 obj){
return new Object3{number=obj.number+1};
}
public Object3 overloaded(Object2 obj){
return new Object3{number=obj.number+2};
}
This works, but seems hacky to me. Wondering what the best way is!
Dependency Injection
interface IObject
{
int number {get;set;}
}
public class Object1 : IObject {
public int number{get;set;}
}
public class Object2 : IObject {
public int number{get;set;}
}
public class Object3 : IObject {
public int number{get;set;}
}
public IObject overloaded(IObject obj){
// Run very specific things to Object1
return new IObject {number=obj.number+1};
}

Categories

Resources