Here is a sample code :
class Program
{
public class A : I {
string a = "myClassA";
// whatever
}
public class B : I
{
string b = "myClassB";
// whatever
}
public interface I
{
// whatever
}
public static void myFunction<T>(List<T> list)
{
Console.WriteLine(list[0].GetType().Name); // OUTPUT : A
Console.WriteLine(JsonConvert.SerializeObject(list[0])); // OUTPUT : {}
}
static void Main(string[] args)
{
List<I> myList = new List<I>();
myList.Add(new A());
myFunction(myList); // arguments mismatch ERROR
}
}
I need this function to output a JSON with appropriate fields (here it should be {"a":"myClassA"}
How should I do ?
EDIT
My real context :
List<string> JSONElements = new List<string>();
List<I> myList = null;
getDataInList(ref myList);
listToJSON(myList, ref JSONElements);
// ...
public void getDataInList(ref List<I> theList) {
// insert data in list
// every elements will be A or every elements will be B
}
// ...
public void listToJSON(List<I> myList, ref List<string> JSONElements) {
foreach (var element in myList) {
// I want every field to be included
// interface has no fields
JSONElements.Add(JsonConvert.SerializeObject(element));
}
}
This function "listToJSON" wont serialize correctly (every elements will be {})
How can I fix this ?
Can you keep
public void myFunction(List<I> list)
(as I not T) and then change
List<A> myList = new List<A>();
to
List<I> myList = new List<I>();
?
In reply to your edit following is printed out by the code at the bottom:
{"Word":"hello","Number":1}
{"Word":"goodbye","Number":2}
Done, press any key...
I am using Newtonsoft.JSon version 6.0.0.0 from the NuGet feed at https://www.nuget.org/api/v2/.
However, when I change public string Word { get; set; } to string Word { get { return "Hello"; } } then Word is not serialised. I don't know how the newtonsoft JSON serialiser works "under the hood", but I imagine that if the field is private then it might have more difficulty (de)serialising it.
public class Program
{
public class A : I
{
public string Word { get; set; }
public int Number { get; set; }
}
public interface I
{
int Number { get; set; }
}
public static void listToJSON(List<I> myList, ref List<string> JSONElements)
{
foreach (var element in myList) {
JSONElements.Add(JsonConvert.SerializeObject(element));
}
}
static void Main(string[] args)
{
List<I> myList = new List<I>();
myList.Add(new A { Word = "hello", Number = 1});
myList.Add(new A { Word = "goodbye", Number = 2});
List<string> jsonElements = new List<string>();
listToJSON(myList, ref jsonElements);
Console.WriteLine(string.Join("\n", jsonElements));
Console.WriteLine("Done, press any key...");
Console.ReadKey();
}
}
I think the reason is best demonstrated by
public void myFunction(List<I> list)
{
list.Add(new B());
}
Related
The following code illustrates a situation I'm having. The real code use different names and get values in other ways, but they match with what I need an answer. Specifically in lines 76-89 (the only lines I control) I need to extract a variable of type "ICollection" with the values and I don't like none of the used approaches. Is there another approach to do it without to create class "AbstractCollection"?
namespace ConsoleApp1
{
using System.Collections.Generic;
using System.Linq;
interface IEntity
{
string Id { get; }
string Name { get; }
}
class Entity : IEntity
{
public Entity(string id, string name)
{
Id = id;
Name = name;
}
public string Id { get; }
public string Name { get; }
}
interface ICollection<TGeneric>
{
IEnumerable<TGeneric> Items { get; }
}
class Collection<TGeneric> : ICollection<TGeneric> where TGeneric : Entity, IEntity
{
public IEnumerable<TGeneric> Items { get; set; }
}
class AbstractCollection<TConcrete, TAbstract> : ICollection<TAbstract> where TAbstract : class, IEntity
{
public AbstractCollection(ICollection<TConcrete> collection)
{
this._Items = new List<TAbstract>();
if (collection?.Items != null)
{
foreach (TConcrete concreteItem in collection.Items)
{
TAbstract abstractItem = concreteItem as TAbstract;
this._Items.Add(abstractItem);
}
}
}
public IEnumerable<TAbstract> Items
{
get { return this._Items; }
set { this._Items = value?.ToList(); }
}
private IList<TAbstract> _Items { get; set; }
}
class EntityCollection : Collection<Entity>
{
public EntityCollection()
{
var items = new List<Entity>()
{
new Entity("1", "Name1"),
new Entity("2", "Name2"),
new Entity("3", "Name3")
};
Items = items;
}
}
class Context
{
public Context()
{
var concreteItems = new EntityCollection();
// I can modify from this line to the end of the method but not any code before.
// I expected values in "list1" but is null.
var list1 = concreteItems as ICollection<IEntity>;
var list2 = concreteItems as ICollection<Entity>;
var abstractItems = new List<IEntity>();
foreach (Entity concreteItem in concreteItems.Items)
{
IEntity abstractItem = concreteItem as IEntity;
abstractItems.Add(abstractItem);
}
// Why "list3" is null?
var list3 = abstractItems as ICollection<IEntity>;
// I want to avoid class "AbstractCollection"
var list4 = new AbstractCollection<Entity, IEntity>(list2);
// Finally "list5" has value in the way I want it.
var list5 = list4 as ICollection<IEntity>;
}
}
class Program
{
static void Main(string[] args)
{
var context = new Context();
}
}
}
Covariance guides to the solution:
interface ICollection<out TGeneric>
{
IEnumerable<TGeneric> Items { get; }
}
I have a class with two variables: Name, Address
I instantiate the class, add values to it, and try to store it in a list. Once I do that I hope to print the Name and Adress on the console but I'm not sure what I'm doing wrong:
public class Test
{
public string Name { set; get; }
public string Address { set; get; }
}
static void Main(string[] args)
{
Test t = new Test();
t.Name = "bob";
t.Address = "CT";
List<Test> lst = new List<Test>();
lst.Add(t);
foreach (var x in lst)
{
Console.WriteLine(x);
}
}
WHen I do this I simply get the name of my project.ClassName
Simply, override ToString and everything else should work as you'd expect it to.
Example:
class Test
{
public string Name { set; get; }
public string Address { set; get; }
public override string ToString(){
return $"name: {Name}, address: {Address}";
}
}
You can utilize the ToString in your class. When passed your class-instance to the Console.WriteLine function, this ToString-function is called.
For further information check the documentation for Console.WriteLine and object.ToString().
public class Test
{
public string Name { set; get; }
public string Address { set; get; }
public override string ToString()
{
return $"Name: {Name} Address: {Address}";
}
}
static void Main(string[] args)
{
Test t = new Test();
t.Name = "bob";
t.Address = "CT";
List<Test> lst = new List<Test>();
lst.Add(t);
foreach (var x in lst)
{
Console.WriteLine(x);
}
}
This will output:
Name: bob Address: CT
You need to access the Name property inside for loop
foreach (var x in lst)
{
Console.WriteLine(x.Name);
}
for me i will use this
static void Main(string[] args)
{
Test t = new Test();
t.Name = "bob";
t.Address = "CT";
List<Test> lst = new List<Test>();
lst.Add(t);
lst.ForEach(show);
}
private static void show(Test obj)
{
Console.WriteLine(obj.Name);
Console.WriteLine(obj.Address);
}
If you want to have it print the properties dynamically whenever the class is updated, you can use Json.Net.
class Test
{
public string Name { set; get; }
public string Address { set; get; }
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
I want to store a list of functions with their parameter value and later when I am done adding function to the list. I want to execute all in the order I have added.
For example, I want to use func instead of action and don't want to create anonymous functions while calling parametered function:
Dynamic function list class to hold a function list and execute it later.
class DynamicFunctionList
{
public List<Action> DynamicList = new List<Action>();
public void Execute()
{
foreach (var obj in DynamicList)
{
obj();
}
}
}
some class with functions
public class SomeClass
{
public void PrintHello()
{
Console.Write("Hello");
}
public void PrintBye()
{
Console.Write("Print Bye");
}
public int GetPrinterValue()
{
return 2;
}
public int Add(int a, int b)
{
return (a + b);
}
}
And this is how you will use it
public static void MainClass()
{
var first = 0;
var second = 0;
var dfList = new DynamicFunctionList();
var sClass = new SomeClass();
dfList.DynamicList.Add(() => first = sClass.GetPrinterValue()); // problem line
dfList.DynamicList.Add(sClass.PrintBye);
dfList.DynamicList.Add(sClass.PrintHello);
dfList.DynamicList.Add(() => second = sClass.Add(2, 3)); // problem
dfList.Execute();
}
I do something like that:
public void main()
{
List<MethodInvoker> methods = new List<MethodInvoker>();
methods.Add(new MethodInvoker(SomeMethod));
foreach (var method in methods)
{
method.Invoke();
}
}
public void SomeMethod()
{
//... do something
}
EDIT 1:
You can use MethodBase.Invoke from System.Reflection namespace (more infos: https://msdn.microsoft.com/en-us/library/a89hcwhh%28v=vs.110%29.aspx)
You can do something like that:
public class DynamicMethod
{
public string ClassName { get; set; }
public string MethodName { get; set; }
public object[] Parameters { get; set; }
public static object InvokeMethod(DynamicMethod methodInfo)
{
var magicType = Type.GetType(methodInfo.ClassName);
var magicConstructor = magicType.GetConstructor(Type.EmptyTypes);
var magicInstance = magicConstructor.Invoke(new object[] {});
var magicMethod = magicType.GetMethod(methodInfo.MethodName);
return magicMethod.Invoke(magicInstance, methodInfo.Parameters);
}
}
public class Example
{
public static void main()
{
var d1 = new DynamicMethod
{
ClassName = "SomeClass",
MethodName = "Add",
Parameters = new object[] { 1, 2 }
};
var returnedValue = DynamicMethod.InvokeMethod(d1);
Console.WriteLine(returnedValue.ToString());
}
Also you can add more information to this class, like some way to store the returned type to do the properly cast.
Let supppose that we have simple class as below:
public class Foo
{
public List<int> l { get; set; }
public Foo(List<int> newList)
{
this.l = newList;
}
}
now we can use it:
List<int> l = new List<int>() { 1, 2 };
Foo foo = new Foo(l);
foreach (int i in foo.l)
Console.WriteLine(i);
Of course, on console we see
1
2
But if we change list l:
l[0] = 11;
l[1] = 22;
and invoke loop again:
foreach (int i in foo.l)
Console.WriteLine(i);
we have on console
11
22
Thus, the list in foo class is changed. Is there any possibility in C#, to see on console again
1
2
so make class Foo such that, the list will be never changed ?
First things first: this is C# and you cannot protect your code against malicious misuse. You can however, make it user-friendly by making it difficult to misuse. For example by using the interface that fulfills all criteria... and not more:
public class Foo
{
public IEnumerable<int> Numbers { get; private set; }
public Foo(IEnumerable<int> numbers)
{
this.Numbers = numbers;
}
}
You can copy the input list, make the setter private and expose an IReadOnlyList<T>:
public class Foo
{
public IReadOnlyList<int> l { get; private set; }
public Foo(IEnumerable<int> newList)
{
this.l = new ReadOnlyCollection<int>(newList.ToList());
}
}
public class Foo
{
private List<int> _l;
public IList<int> L { get { return this._l.AsReadOnly(); } }
public Foo(List<int> newList)
{
this._l = new List<int>(newList);
}
}
You could dress your private variable with a readonly property, or not include the "set" action on your property.
What you actually need is this option #1 or #2
1
private readonly List<int> _l;
public List<int> l { get; set; }
2
public List<int> l { get; }
MSDN readonly prop link
I have a class:
public class Test1
{
public void assignData(List<CustomClass> customData, string targetFieldName)
{
for(int i=0; i<customData.Count; i++)
{
if(customData[i].targetFieldName)
{
customData[i].targetFieldName = newValue;
}
}
}
}
List<customClass1> list1;
List<customClass2> list2;
customClass1 and customClass2 are completely different, but they share the same field 'dateAdded'. I want to be able to call Test1.assignData(list1, "dateAdded") and Test1.assignData(list2, "dateAdded"). and the list1 and list2 will get updated. How can I do that? Thanks!
The best way to do this is to have a common interface that they both implement which exposes the dateAdded field as a property
interface ICustomClass {
DateTime dateAdded { get; set; }
}
Then both classes can implement that interface and you can change the function to use that interface
public void assignData(IEnumerable<ICustomClass> enumerable) {
foreach (var customData in enumerable) {
customData.dateAdded = newValue;
}
}
EDIT
In the comments the OP stated their desire to make this update to any list irrespective of the interface. In that case the likely best course is to use dynamic
public void assignData(IEnumerable<object> enumerable) {
foreach (dynamic customData in enumerable) {
try {
customData.dateAdded = newValue;
} catch {
// Object doesn't have dateAdded so just move on
}
}
}
If CustomClass1 and CustomClass2both deriving from CustomClass and you want to simply set value of targetFieldName , all you need to do is replace List<T> with IEnumerable<T>.
Make sure the common field is in base class so that it can be accessed without worrying about the derived implementation.
public void assignData(List<CustomClass> customData, string targetFieldName)
with
public void assignData(IEnumerable<CustomClass> customData,
string targetFieldName)
With this you can call it for both lists because of covariance. Simple example -
IEnumerable<object> list = new List<string>(); // This will work
List<object> list = new List<string>(); // This won't compile.
So I totally agree with #JaredPar that this sounds like you need a common interface but it is possible with dynamics.
Note that this example code doesn't behave properly if DateAdded isn't present
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace dynamics_test
{
class CustomOne
{
public string NotInCustomTwo { get; set; }
public DateTime DateAdded { get; set; }
}
class CustomTwo
{
public string NotInCustomOne { get; set; }
public DateTime DateAdded { get; set; }
}
[TestFixture]
public class TestDynamics
{
private List<CustomOne> _customOnes;
private List<CustomTwo> _customTwos;
[SetUp]
public void Setup()
{
this._customOnes = new List<CustomOne>()
{
new CustomOne {DateAdded = DateTime.Now.AddDays(1), NotInCustomTwo = "some value"},
new CustomOne {DateAdded = DateTime.Now, NotInCustomTwo = "some value"}
};
this._customTwos = new List<CustomTwo>()
{
new CustomTwo {DateAdded = DateTime.Now.AddDays(1), NotInCustomOne = "some value"},
new CustomTwo {DateAdded = DateTime.Now, NotInCustomOne = "some value"}
};
}
[Test]
public void DynamicsAllowBadThingsMkay()
{
var dynamics = _customOnes.Cast<dynamic>().ToList();
dynamics.AddRange(_customTwos);
Assert.AreEqual(2, dynamics.Count(d=>d.DateAdded.Date == DateTime.Now.Date));
foreach (var thing in dynamics)
{
Console.WriteLine(thing.DateAdded);
}
}
}
}