I've been working on using reflection but its very new to me still. So the line below works. It returns a list of DataBlockOne
var endResult =(List<DataBlockOne>)allData.GetType()
.GetProperty("One")
.GetValue(allData);
But I don't know myType until run time. So my thoughts were the below code to get the type from the object returned and cast that type as a list of DataBlockOne.
List<DataBlockOne> one = new List<DataBlockOne>();
one.Add(new DataBlockOne { id = 1 });
List<DataBlockTwo> two = new List<DataBlockTwo>();
two.Add(new DataBlockTwo { id = 2 });
AllData allData = new AllData
{
One = one,
Two = two
};
var result = allData.GetType().GetProperty("One").GetValue(allData);
Type thisType = result.GetType().GetGenericArguments().Single();
Note I don't know the list type below. I just used DataBlockOne as an example
var endResult =(List<DataBlockOne>)allData.GetType() // this could be List<DataBlockTwo> as well as List<DataBlockOne>
.GetProperty("One")
.GetValue(allData);
I need to cast so I can search the list later (this will error if you don't cast the returned object)
if (endResult.Count > 0)
{
var search = endResult.Where(whereExpression);
}
I'm confusing the class Type and the type used in list. Can someone point me in the right direction to get a type at run time and set that as my type for a list?
Class definition:
public class AllData
{
public List<DataBlockOne> One { get; set; }
public List<DataBlockTwo> Two { get; set; }
}
public class DataBlockOne
{
public int id { get; set; }
}
public class DataBlockTwo
{
public int id { get; set; }
}
You might need something like this:
var endResult = Convert.ChangeType(allData.GetType().GetProperty("One").GetValue(allData), allData.GetType());
Just guessing, didn't work in C# since 2013, please don't shoot :)
You probably want something like this:
static void Main(string[] args)
{
var one = new List<DataBlockBase>();
one.Add(new DataBlockOne { Id = 1, CustomPropertyDataBlockOne = 314 });
var two = new List<DataBlockBase>();
two.Add(new DataBlockTwo { Id = 2, CustomPropertyDatablockTwo = long.MaxValue });
AllData allData = new AllData
{
One = one,
Two = two
};
#region Access Base Class Properties
var result = (DataBlockBase)allData.GetType().GetProperty("One").GetValue(allData);
var oneId = result.Id;
#endregion
#region Switch Into Custom Class Properties
if (result is DataBlockTwo)
{
var thisId = result.Id;
var thisCustomPropertyTwo = ((DataBlockTwo)result).CustomPropertyDatablockTwo;
}
if (result is DataBlockOne)
{
var thisId = result.Id;
var thisCustomPropertyOne = ((DataBlockOne)result).CustomPropertyDataBlockOne;
}
#endregion
Console.Read();
}
public class AllData
{
public List<DataBlockBase> One { get; set; }
public List<DataBlockBase> Two { get; set; }
}
public class DataBlockOne : DataBlockBase
{
public int CustomPropertyDataBlockOne { get; set; }
}
public class DataBlockTwo : DataBlockBase
{
public long CustomPropertyDatablockTwo { get; set; }
}
public abstract class DataBlockBase
{
public int Id { get; set; }
}
Related
I have a generic class, JSTable, that takes a type RowType. I want to have a class that can contain many JSTables, each with a different RowType, so that I may do something like the Func<> in C# does, where it has many optional types. Is this only possible because there are many representations of Func<>? I want a limitless option, so that I could potentially declare a JSGridVM with hundreds of tables, or one table.
public class JSGridVM<?>//where ? is as many types as I want
{
public List<JSTable<?>> Tables { get; set; };
}
public class JSTable<RowType>
{
public JSTable() { }
public JSTable(List<RowType> rows, List<JSGridColumn> columns, bool allowEditingRows, bool allowDeletingRows, string updateURL, string deleteURL)
{
Rows = rows;
Columns = columns;
AllowEditingRows = allowEditingRows;
AllowDeletingRows = allowDeletingRows;
UpdateURL = updateURL;
DeleteURL = deleteURL;
}
public List<RowType> Rows { get; set; }
public List<JSGridColumn> Columns { get; set; }
public bool AllowEditingRows { get; set; }
public bool AllowDeletingRows { get; set; }
public string UpdateURL { get; set; }
public string DeleteURL { get; set; }
}
public class JSGridColumn
{
public string PropertyName { get; set; }
public ColumnType Type { get; set; }
}
public enum ColumnType
{
Text,
Hidden,
}
Then declare like
var jsGridVM = new JSGridVM<SomeClass1, SomeClass2, SomeClass3>();
OR
var jsGridVM = new JSGridVM<SomeClass1>();
You should declare generic type argument <RowType> not at class level, but at methods: AddTable and GetTable:
public class JSGridVM
{
private Dictionary<Type, object> Tables = new Dictionary<Type, object>();
public JSGridVM AddJSTable<RowType>()
{
Tables.Add(typeof(RowType), new JSTable<RowType>());
return this;
}
public JSTable<RowType> GetJSTable<RowType>()
{
Tables.TryGetValue(typeof(RowType), out object temp);
return (JSTable<RowType>)temp;
}
}
Usage:
var sample = new JSGridVM();
sample.AddJSTable<RowTypeA>().AddJSTable<RowTypeB>();
var test = a.GetJSTable<RowTypeA>();
You could roll your own class, but the .NET DataSet class might be what you are after. DataSet has been around for ages and is still pretty useful.
var ds = new DataSet();
var dataTable = new DataTable("DataTable");
var stringCol = new DataColumn("String Column", typeof(string));
var intCol = new DataColumn("Integer Column", typeof(int));
var decimalCol = new DataColumn("Decimal Column", typeof(decimal));
dataTable.Columns.AddRange(new [] {stringCol, intCol, decimalCol});
var newRow = new object[]
{
"String item",
1,
100.08m
};
dataTable.Rows.Add(newRow);
ds.Tables.Add(dataTable);
var row = ds.Tables["DataTable"].Rows[0];
var stringRowValue = row["String Column"];
var intRowValue = row["Integer Column"];
var decimalRowValue = row["Decimal Column"];
Console.WriteLine($"String value: {stringRowValue}\nInteger value: {intRowValue}\nDecimal Value: {decimalRowValue}");
var rowArr = new DataRow[ds.Tables["DataTable"].Rows.Count];
ds.Tables["DataTable"].Rows.CopyTo(rowArr, 0);
var list = rowArr.ToList();
foreach (DataRow rowitem in list)
{
Console.WriteLine($"\nFrom List: String value: {rowitem["String Column"]}\nInteger value: {rowitem["String Column"]}\nDecimal Value: {rowitem["String Column"]}");
}
Console.ReadKey();
Not sure what you are trying to accomplish, but this is already pretty robust. If you are trying to accomplish a specific use case by creating a generic class, then check out MSDN for more help.
Using Generics:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-type-parameters
Func:
https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx
Why not :
public class JSGridVM<JSTable>
{
public List<JSTable> Tables { get; set; };
}
public class JSTable<?>
{
}
var rowTypeAnimals = AnimalRowType();
var rowTypeBirds = BirdRowType();
var animalTable = new JSTable<AnimalRowType>(){rowTypeAnimals };
var birdTable = new JSTable<BirdRowType>(){rowTypeBirds };
var grid = new JSGridVM(){animalTable,birdTable};
Keep the row type generic for your table and your grid will always have the same JSTable type.
I have the following classes
public enum Category { foo, foo1, foo2 }
public class Event
{
public DateTime Timestamp { get; set; } = DateTime.Now;
public string GameTime { get; set; }
public string Content { get; set; }
public Person Author { get; set; }
public Category Category { get; set; }
}
and
public class MemberEvent : Event
{
public Member Person { get; set; }
}
The object is created correctly, but if I want to call "Person", this is not displayed to me. If I have a var match, I can call for example match[0].Timestamp but not match[0].Person. The Event object is stored in a List, therefore also the index. I feel I'm missing something simple.
UPDATE: The Code that create the Object
var match = SessionController.Instance.Current;
DataTable dt = dataGrid.ItemsSource as DataTable;
foreach (System.Data.DataRow item in dt.Rows)
{
var memberFoo = new MemberEvent();
memberFoo.Category = Category.Warning;
memberFoo.Time = item["Time"].ToString();
var person = new Person();
person.FirstName = item["FirstName"].ToString();
person.LastName = item["LastName"].ToString();
var passport = new Passport();
passport.Active = true;
passport.PassNumber = item["Pass"].ToString();
passport.Player = person;
memberFoo.Person = passport;
match.Match.Events.Add(memberFoo);
}
SessionController.Instance.Current = match;
Cast your instance to the expected type and test for null to guard for the unexpected:
var memberEvent = match[0] as MemberEvent;
if (memberEvent != null)
{
Console.WriteLine(memberEvent.Person)
}
You will have to cast your Event into a MemberEvent if you want to access the Person property. It is not possible to get the property from Event.
List<Event> myEvents = GetMyEvents();
var myMemberEvent = (MemberEvent)myEvent[0];
It can cause an exception if it can't convert to MemberEvent.
Let me explain, I have a model list in which I have a little more than a thousand parameters, so I have to fill the list with some variables, the thing is that I don't want to do this:
list.Add(new Model{
name1= value,
name2= value,
.....
name1000=value
});
I have an array that contains the names of the parameters in the list, so I was wondering if is possible to use that array of the names and in a loop get the variables fill in, something like this:
list.Add(new Model{
//a loop?
array[0]= value
});
Thanks.
You can achieve this using reflection. Code below
public class ModelFactory
{
private IDictionary<string, PropertyInfo> propertiesInfo { get; set; }
public ModelFactory()
{
this.propertiesInfo = typeof(Model)
.GetProperties()
.ToDictionary(p => p.Name, p => p);
}
public Model Create(string[] propertiesToInitialize, dynamic value)
{
var model = new Model();
foreach (var propertyName in propertiesToInitialize)
{
if (this.propertiesInfo.ContainsKey(propertyName))
{
var property = this.propertiesInfo[propertyName];
property.SetValue(model, value);
}
}
return model;
}
}
Model to initialize
public class Model
{
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
public int MyProperty4 { get; set; }
public int MyProperty5 { get; set; }
}
Usage
public void Test()
{
var propertiesToInitialize = new string[] { "MyProperty1", "MyProperty2", "MyProperty4" };
var modelFactory = new ModelFactory();
var list = new List<Model>();
list.Add(modelFactory.Create(propertiesToInitialize, 500));
Console.WriteLine("MyProperty1 " + list[0].MyProperty1); // 500
Console.WriteLine("MyProperty2 " + list[0].MyProperty2); // 500
Console.WriteLine("MyProperty3 " + list[0].MyProperty3); // 0
Console.WriteLine("MyProperty4 " + list[0].MyProperty4); // 500
Console.WriteLine("MyProperty5 " + list[0].MyProperty5); // 0
}
However as already mentioned in comments, please reconsider your model design because model with these many properties is not optimal.
I'm trying to create an object and insert to the database but keep getting the same error no matter what I try.
The row that I get the error on is ColumnGroupTest.ValidValues.Add(memberComment1); the error is
error message
NullReferenceException was unhandled by user code
my models
public class StoreColumnName
{
public int Id { get; set; }
public string StoreColumnGroupName { get; set; }
public string ColumnName { get; set; }
public string ColumnType { get; set; }
public List<StoreValidValue> ValidValues { get; set; }
}
public class StoreValidValue
{
public int Id { get; set; }
public string ValidValue { get; set; }
public StoreColumnName StoreColumnName { get; set; }
}
my controller
public ActionResult Index()
{
XDocument document = XDocument.Load(#"C:\Users\Physical.xml");
var result = document.Descendants("ColumnGroup");
foreach(var item in result){
var ColumnGroupName = item.Attribute("name").Value;
var Columns = item.Descendants("Column");
foreach (var itemColumn in Columns)
{
StoreColumnName ColumnGroup = new StoreColumnName();
var ColumnGroupTest = new StoreColumnName
{
StoreColumnGroupName = ColumnGroupName,
ColumnName = itemColumn.Attribute("name").Value,
ColumnType = itemColumn.Attribute("type").Value,
Id = 11
};
var ValidValues = itemColumn.Descendants("ValidValues");
var Values = ValidValues.Descendants("Value");
foreach (var Value in Values)
{
var memberComment1 = new StoreValidValue
{
StoreColumnName = ColumnGroupTest,
ValidValue = Value.Value,
Id = 101
};
ColumnGroupTest.ValidValues.Add(memberComment1);
}
}
}
return View();
}
(I gladly take tips on what I can improve when asking for help/guiding here).
Can anyone help ?
The issue that you're having is that you don't initialize your ValidValues property to a list. By default, those types of properties initialize to null unless you specify differently.
The best approach is to add that initialization to your constructor of that object.
public StoreColumnName() {
this.ValidValues = new List<StoreValidValue>();
}
I need a way to get the values from a generic HashSet using reflection. Here is what I've tried (you can copy/paste this on a console app):
class Program
{
public class Order
{
public int Id { get; set; }
}
public class Person
{
public string Name { get; set; }
public ICollection<Order> Orders { get; set; }
}
static void Main(string[] args)
{
var person = new Person();
person.Name = "Test Person";
person.Orders = new HashSet<Order>();
person.Orders.Add(new Order() { Id = 1 });
person.Orders.Add(new Order() { Id = 2 });
var reflectedOrders = person.GetType().GetProperty("Orders").GetValue(person, null);
Console.WriteLine("How do I iterate the reflected orders?");
Console.ReadLine();
}
}
EDIT
It's an example, in the real application I don't know which type to convert the reflected Orders. I only know the property is an ICollection<T> (turned to HashShet by EF)
Did you tried casting reflectedOrders to IEnumerable?
IEnumerable reflectedOrders = (IEnumerable)person.GetType().GetProperty("Orders").GetValue(person, null);
It should be simple as casting:
var reflectedOrders = (HashSet<Order>) person.GetType().GetProperty("Orders").GetValue(person, null);
foreach (var order in reflectedOrders)
...
What about
var orders = persons.OfType<Person>().SelectMany(p => p.Orders);