Get subclass content from object - c#

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.

Related

Cannot implicitly convert type IQueryable to class

I am trying to get multiple results into a list to send back to JS to populate a grid. The first query (_mappedQuery) is getting data. I then want to end up putting the values into the _udfList object. I keep getting variances on the error 'cannot convert queryable to class'
I have tried setting as lists, creating query objects, single class objects. All no luck so far
MemberMNCFormsList _udfList = new MemberMNCFormsList();
foreach (var _row in _udfTables) {
System.Diagnostics.Debugger.Break();
System.Diagnostics.Debugger.Launch();
var _mappedQuery = (from res in Query<UdfColumnMapping>().AsNoTracking()
join udf in Query<UserDefinedForms>().AsNoTracking() on res.Func_Area equals udf.Func_Area
join ds in Query<Data_Set>().AsNoTracking() on res.Data_ID equals ds.DATA_ID
join df in Query<DEFITEM>().AsNoTracking() on ds.DEF_ID equals df.DEF_ID
where udf.UserDefinedForms_ID == _row.UserDefinedForms_ID &&
(res.FieldName.ToLower().StartsWith("reviewname") ||
res.FieldName.ToLower().StartsWith("disposition") ||
res.FieldName.ToLower().StartsWith("reviewdate"))
select (new MemberMNCForms {
UserDefinedFormData_ID = _row.UserDefinedFormData_ID,
FormId = udf.UserDefinedForms_ID,
MappedColumnName = res.MappedColumnName,
FieldName = res.FieldName,
MappedTableName = res.MappedTableName,
Reviewed_Name = _row.LAST_NAME.Trim() + ", " + _row.FIRST_NAME.Trim(),
Reviewed_Date = _row.CreateDate.GetShortDateorEmpty().ToString()
}));
var _formRow = _mappedQuery.Select(t => new MemberMNCForms {
UserDefinedFormData_ID = t.UserDefinedFormData_ID,
FormId = t.FormId,
MappedColumnName = t.MappedColumnName,
FieldName = t.FieldName,
MappedTableName = t.MappedTableName,
Reviewed_Name = t.Reviewed_Name,
Reviewed_Date = t.Reviewed_Date
})));
_udfList.list.Add(_formRow);
public sealed class MemberMNCForms {
public Guid? UserDefinedFormData_ID { get; set; }
public int FormId { get; set; }
public string Reviewed_Name { get; set; }
public string MappedColumnName { get; set; }
public string FieldName { get; set; }
public string MappedTableName { get; set; }
public int? MNCDetermination_ID { get; set; }
public string Reviewed_By { get; set; }
public string Reviewed_Date { get; set; }
}
public sealed class MemberMNCFormsList : ErrorInfo
{
public List<MemberMNCForms> list = new List<MemberMNCForms>();
public int Count { get; set; }
}
I am trying to get the _udfList object populated with the values coming from _mappedQuery. The only thing I thought would work was to create a MemberMNCForms object for each record in _mappedQuery to then add to _udfList.list
_formRow is an IEnumerable<MemberMNCForms>
var _formRow = _mappedQuery.Select(t => new MemberMNCForms {
UserDefinedFormData_ID = t.UserDefinedFormData_ID,
FormId = t.FormId,
MappedColumnName = t.MappedColumnName,
FieldName = t.FieldName,
MappedTableName = t.MappedTableName,
Reviewed_Name = t.Reviewed_Name,
Reviewed_Date = t.Reviewed_Date
})));
Here you are trying to add an IEnumerable<MemberMNCForms> to a List<MemberMNCForms>
_udfList.list.Add(_formRow);
You can't do this with .Add. You have to use .AddRange
Try this:
_udfList.list.AddRange(_formRow);
When you use linq like that, even if there is a single item in the list that you are Selecting on, it is just an expression tree until it is iterated on.
I assume that you are expecting a collection of MemberMNCForms back so you would need use AddRange instead of Add
_udfList.list.AddRange(_formRow);
To make sure that it has been executed, you can use ToList
_udfList.list.AddRange(_formRow.ToList());
If you are just expecting a single result, you can use SingleOrDefault.
var result = _formRow.SingleOrDefault();
if (result != null) {
_udfList.list.Add(result);
}

Casting List Type at Runtime C# Reflection

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

Write an Observable Collection to Csv file

I have a datagridview that is bound to an observable collection in a mvvm fashion.
I'm trying to figure out how to write the collection to a csv file.
I can format the headers and get that put in, but not sure how one would iterate over a collection pulling out the values and putting them to a file with comma delimiting.
Here is my class
public class ResultsModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Phone { get; set; }
public string Username { get; set; }
public bool Sucess { get; set; }
public string MessageType { get; set; }
public string SenderMessageSent { get; set; }
public string SenderMessageReceived { get; set; }
}
which gets loaded into an observable collection
Here's a generic helper method which utilizes reflection to get values of all properties in the collection of objects and serializes to comma separated values string. (1 line = 1 object from collection)
public static IEnumerable<string> ToCsv<T>(IEnumerable<T> list)
{
var fields = typeof(T).GetFields();
var properties = typeof(T).GetProperties();
foreach (var #object in list)
{
yield return string.Join(",",
fields.Select(x => (x.GetValue(#object) ?? string.Empty).ToString())
.Concat(properties.Select(p => (p.GetValue(#object, null) ?? string.Empty).ToString()))
.ToArray());
}
}
And the examplary usage:
var oemResultsModels = new List<OemResultsModel>
{
new OemResultsModel
{
FirstName = "Fname1",
LastName = "LName1",
MessageType = "Type1",
Phone = 1234567,
SenderMessageReceived = "something1",
SenderMessageSent = "somethingelse1",
Sucess = true,
Username = "username1"
},
new OemResultsModel
{
FirstName = "Fname2",
LastName = "LName2",
MessageType = "Type2",
Phone = 123456789,
SenderMessageReceived = "something2",
SenderMessageSent = "somethingelse2",
Sucess = false,
Username = "username2"
}
};
using (var textWriter = File.CreateText(#"C:\destinationfile.csv"))
{
foreach (var line in ToCsv(oemResultsModels))
{
textWriter.WriteLine(line);
}
}

How do I create and insert one-to-many object with entity framework c#

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

Set a value of ilist<T> members

I have the following classes:
public class Products
{
public int Id { get; set; }
public string ProductName { get; set; }
public int Price { get; set; }
public IList<ProductFiles> ProductFiles { get; set; }
}
public class ProductFiles
{
public int NumberOfFiles { get; set; }
public int NumberOfShops { get; set; }
}
Here I am trying to set the value of the property NumberOfFiles (member of ProductFiles):
public Products CountProductFiles(int productId)
{
DB_utilities db = new DB_utilities();
object[] spParams = new object[] { productId};
Products product = new Products();
using (var reader = db.procSelect("[Products_CountFiles]", spParams))
{
reader.Read();
{
Products _products = new Products
{
ProductName = (string)reader["ProductName"],
Price = (double)reader["Price"],
// I am trying to do something like this but this does not work:
ProductFiles.NumberOfFiles = (int)reader["NumberOfFiles"]
};
Products = _products ;
}
}
return Products;
}
How can I set the value of the prop NumberOfFiles? Or is the entire concept wrong?
As ProductFiles is a collection of ProductFiles, you need to do this
Products p = new Products();
p.ProductFiles = new List<ProductFiles>();
p.ProductFiles.Add(new ProductFiles() { NumberOfFiles = 1 }); // or some other defined value.
The collection needs to be initialized before adding objects to it.
In your example, you do not treat ProductFiles as a collection, that is why you get the error.
The point of a collection is that it can contain zero or more items. You need to put an instance in the collection. You also need to create a collection to ensure that the collection itself is not null.
new Product {
Files = new List<ProductFile>() {
new ProductFile {
FileCount = 42
}
}
}
In this example, Products::ProductFiles is a list.
Hence, in order to set the value of NumberOfFiles, do something like this:
ProductFiles[i].NumberOfFiles = //whatever you want to set it to.
But, before doing all this, do not forget to instantiate the List variable. Otherwise, it will itself be NULL.

Categories