This question already has answers here:
How to get the type of T from a member of a generic class or method
(17 answers)
Closed 9 years ago.
I'm working on a project where I have to reflect through data models to find out what type is in each property on a data models. I have the code working for all cases except for generic collections. I have to be able to what T is in IList.
I have the following data model
public class ArrryOfObjects
{
public NestModelNestedClass NestClass { get; set; }
public int IntObject { get; set; }
public IList<NestModelNestedClass> ListOfObjects { get; set; }
}
I've seen a couple of examples, like https://stackoverflow.com/a/1043778/136717 on how to do this, but they use the type.GetGenericTypeDefinition() to be get the type. But in my sample I cannot use this because 'type.IsGeneric.Parameter' is false.
I've review Type documentation and don't understand how to do this.
Try this:
var t = typeof(ArrryOfObjects)
.GetProperty("ListOfObjects")
.PropertyType
.GetGenericArguments()[0];
This is how it works:
From the type of ArrryOfObjects...
obtain the property called ListOfObjects...
get the type of that property...
which we know to be a generic type with at least one type parameter.
We get the first type parameter - in your example it should be typeof(NestModelNestedClass)
P.S. GetGenericTypeDefinition gets you typeof(IList<>), the generic type of which IList<NestModelNestedClass> is a generic instance.
Related
This question already has answers here:
Default parameter for value must be a compile time constant?
(7 answers)
Closed 9 months ago.
This post was edited and submitted for review 9 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I'm attempting to build an 'Action' abstract class that will be used in many different ways. An Action, in my case, is just a simple repeatable task that is called by various 'Triggers'. I've also created an 'ActionArgs' class to be used as a structure to hold arguments for the Action to be performed. The default 'ActionArgs' object doesn't contain any arguments, which is intended to act as the default. However, I want to be able to create 'Action's and 'ActionArgs' that inherit from their respective parents, but I always want the base empty ActionArgs object to act as the default value for an optional parameter, as some Actions will have parameters, others might not. I'm having problems achieving this. I've tried a few things, but this is what I'm kind of going for:
public abstract class Action
{
public string Name { get; private set; }
public Action(string name) { Name = name; }
public abstract bool PerformAction(ActionArgs args = ActionArgs.Empty);
}
public class ActionArgs
{
public static readonly ActionArgs Empty = new ActionArgs();
public ActionArgs() { }
}
In attempting this, I get an error on the PerformAction() definition, says that a default parameter value must be a compile-time constant. Why is this impossible to resolve this at compile time? I'm guessing it's because it is assuming the worst that you have some run-time variation in the constructor. In my case I clearly do not, but is there any way that I can approach this in a way that doesn't involve using null as the default parameter?
I would use a method overload:
public abstract class Action
{
public string Name { get; private set; }
public Action(string name) { Name = name; }
public bool PerformAction() => PerformAction(ActionArgs.Empty);
public abstract bool PerformAction(ActionArgs args);
}
This question already has answers here:
How to serialize/deserialize a custom collection with additional properties using Json.Net
(6 answers)
How do I get json.net to serialize members of a class deriving from List<T>?
(3 answers)
Closed 5 years ago.
We're switching our cache system over from a binary serializer (the one AppFabric uses) to a JSON serializer (For use with Redis) and I'm running into some incompatibilities with a few object types. The general idea is the same, we have a class that looks something like this:
[Serializable]
public class ActivityMeasurementIndexes : List<ActivityMeasurementIndex>
{
public int Id { get; set; }
public DateTime lastDbRead { get; set; }
public ActivityMeasurementIndexes()
{
lastDbRead = DateTime.Now;
}
}
The binary serializer will serialize and deserialize the object just fine. However, when I try to serialize the object with JSON.NET, I get:
var testObject = new ActivityMeasurementIndexes { Id = 5 };
Newtonsoft.Json.JsonConvert.SerializeObject(testObject);
"[]"
So, JSON.NET is basically serializing the base List<T> but the properties in the derived type are getting lost. I could probably refactor this class so it has a public List<ActivityMeasurementIndex> Items { get; set } instead, but we have quite a few of these classes and tons of code that would also have to be refactored.
Is there a good approach to handle this? I don't really care how the JSON looks as long as I can serialize and deserialize the base list as well as the properties on the class. I'm guessing I would need to write some sort of custom converter, or maybe there's something JSON.NET can do out of the box to help me out. Any hints for stuff to read up on would be great!
This question already has answers here:
Intersect with a custom IEqualityComparer using Linq
(2 answers)
C# Linq intersect/except with one part of object
(7 answers)
Closed 5 years ago.
I had two DateTime lists and was intersecting them with no problems:
IEnumerable<DateTime> both = list1.Intersect(list2);
I have the custom data type and still need to find the intersection:
public class AssetRecord
{
// Custom data type. Each object has time and price
public DateTime AssetDate { get; set; }
public double AssetPrice { get; set; }
}
// Lits initialization
public static List<AssetRecord> list1 = new List<AssetRecord> { };
// Key/Values - Date/Price. Custom data type is used to store an object in the collection
public static List<AssetRecord> list2 = new List<AssetRecord> { };
The problem is that IEnumerable takes only DataTime lists as an input and I do not have that data type anymore. Is it possible to find intersection using custom types? Or is it possible to take only Date field from created data type and convert it to List and then pass it to IEnumerable?
The problem is that IEnumerable takes only DataTime lists
Huh? That makes no sense. IEnumerable<T> takes whatever T you choose. In this case IEnumerable<AssetRecord> will contain AssetRecords.
Now, that is not your main problem. Your issue is with how intersect works. Enumerable.Intersect<T> takes the default equality of T. So, what is the default equality comparer of AssetRecord? Reference equality, and you probably want value equality semantics.
Solution? Override Equals in AssetRecord accordingly and while your at it implement IEquatable<AssetRecord> too (and don't forget to override GetHashCode with a consistent behavior):
public class AssetRecord: //IEquatable<AssetRecord> left as exercise
{
// Custom data type. Each object has time and price
public DateTime AssetDate { get; set; }
public decimal AssetPrice { get; set; }
public override bool Equals(object other)
{
if (other is AssetRecord)
{
var ass = (AssetRecord)other;
return ass.AssetDate == AssetDate &&
ass.AssetPrice == AssetPrice;
}
return false;
}
public override int GetHashCode()
{
return AssetDate.GetHashCode() ^ AssetPrice.GetHashCode();
}
}
If you can't touch AssetRecord then implement an IEqualityComparer<AssetRecord> and use the corresponding overload of Intersect.
Two more issues with your code worth mentioning:
Prices should be a decimal, not a double. You want exact decimal values, use the right tool provided by the framework.
Your type is already named AssetRecord, it should probably be named Asset, but anyway, there is no need to have properties with redundant information. Price and Date should be enough.
This question already has answers here:
How can I ignore unknown enum values during json deserialization?
(6 answers)
Closed 5 years ago.
So I'm working on a API wrapper with C#, I deserialize JSON data to a response model class using Newtonsoft.Json library. In the response model class, I have a list of sub-items, which each of contain a list of sub-items. These are defined like this:
public List<StatModel> Stats { get; set; }
each StatModel has a property which basically equals the name:
public Stat Stat { get; set; }
these are automatically deserialized, because each Stat is defined in an enum like this:
[EnumMember(Value = "Avg Walk Distance")]
AverageWalkDistance,
Now the problem is, if something changes in the actual API, the wrapper doesn't work since it doesn't have definition for the specified Stat. So this means if they add a new Stat to the API, the wrapper won't work until I manually add definition for it, like in the above code block.
So the question is, how can I ignore values that don't have corresponding Stat property available, or can I somehow re-design the whole thing so this doesn't happen? I'm guessing I have to define all new values by myself either way.
Here's the project on GitHub to get a better understanding of what I actually mean: https://github.com/eklypss/PUBGSharp
The Requester does the deserializing and returns a StatResponse, which has a list of sub-items called StatsRoot which each have their own list of StatModels which are the actual stat objects causing this issue. Each type of Stat is defined in the Enum/Stat.cs file.
If you don't want to create your own tolerant version of StringEnumConverter, you could use Json.NET's exception handling features:
public class StatModel
{
const string StatName = "label";
[JsonProperty(StatName)]
[JsonConverter(typeof(StringEnumConverter))]
public Stat Stat { get; set; }
public string Value { get; set; }
public int? Rank { get; set; }
public double? Percentile { get; set; }
[OnError]
void OnError(StreamingContext context, ErrorContext errorContext)
{
if (errorContext.OriginalObject == this && StatName.Equals(errorContext.Member))
{
errorContext.Handled = true;
}
}
}
When an exception is thrown while deserializing StatModel or any of its nested objects, its OnError() method will be called to possibly handle the error. The method checks to see whether the exception was thrown
While deserializing this specific object, AND
While deserializing the "label" member.
If so, the exception is swallowed. You could also take the opportunity to set a flag in the model indicating that the Stat property was invalid.
You can have json.net ignore missing members.
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore
};
var json = JsonConvert.DeserializeObject<MyClass>(jsonStr, settings);
Refer to the question below, this guy had same issues as you have.
How can I ignore unknown enum values during json deserialization?
However,
Even if you somehow manage to ignore new Stats, it's not good for your wrapper as consumers of your wrapper need to wait for you to add that new Enum.
So,
If I were you, I would think to change Stat from Enum to string, so whenever a new Stat comes, neither you need to change anything nor consumers of your wrapper, would not have to wait.
This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
Is there a way to define an implicit conversion operator in VB.NET?
I can't remember ever seeing or hearing of anyone do this; but now I'm in a situation where I think it would be incredibly useful to define my own custom 'type conversion' for my class.
As an example - let's say I have my own class, 'AwesomeDataManager'. It does not inherit from DataTable, but it holds data in a similar fashion to a DataTable. I would to be able to say, 'myDataTable = CType(MyAwesomeDataManager, DataTable)' and have it execute some code inside my class that would return a populated DataTable.
Granted, I could do something like 'MyAwesomeDataManager.GetDataTable' but for the sake of integrating with an existing code base, I'd like to avoid it.
You could use an implicit or explicit cast, like this: (Note that LetMeChange is implicitly cast to SomethingMoreComfortable)
class Program
{
static void Main(string[] args)
{
LetMeChange original = new LetMeChange { Name = "Bob" };
SomethingMoreComfortable casted = original;
Console.WriteLine(casted.Name);
}
}
public class LetMeChange
{
public static implicit operator SomethingMoreComfortable(LetMeChange original)
{
return new SomethingMoreComfortable() { Name = original.Name };
}
public string Name
{
get;
set;
}
}
public class SomethingMoreComfortable
{
public string Name
{
get;
set;
}
}
There are two keywords in C# that help with type conversions: implicit and explicit.
In this case, you would want implicit for code eye-candy. Be careful with this however, as it can cause moments of confusion as people realise what you are doing. I tend to not spot the use of implicit conversions just by reading the code quickly (explicit are hard to miss as they need casts).