Attempting to retrieve the Value of an EntryStatus(class further down), ie ("READY", "DELETED", "ERROR_IMPORTING") in a manner similar to the immediately below
EntryStatus test = EntryStatus.DELETED;
Console.WriteLine(test);
EntryStatus value = test;
string val = value.ToString();//see note1
Console.WriteLine(val);
The result of the above code is:
3
3
I would like to have the second Console.WriteLine to return "DELETED"
I do not understand how to retrieve the alphabetic part of the enum.
note1: changing this line to
int val = (int)value;
gives an error of Cannot Convert EntryStatus to int. This enum seems not to behave like other C# enums.
The EntryStatus is child class of StringEnum.
Edit: EntryStatus is part of the Kaltura Generated API and should not be modified.
public sealed class EntryStatus : StringEnum
{
public static readonly EntryStatus ERROR_IMPORTING = new EntryStatus("-2");
public static readonly EntryStatus ERROR_CONVERTING = new EntryStatus("-1");
public static readonly EntryStatus IMPORT = new EntryStatus("0");
public static readonly EntryStatus INFECTED = new EntryStatus("virusScan.Infected");
public static readonly EntryStatus SCAN_FAILURE = new EntryStatus("virusScan.ScanFailure");
public static readonly EntryStatus PRECONVERT = new EntryStatus("1");
public static readonly EntryStatus READY = new EntryStatus("2");
public static readonly EntryStatus DELETED = new EntryStatus("3");
public static readonly EntryStatus PENDING = new EntryStatus("4");
public static readonly EntryStatus MODERATE = new EntryStatus("5");
public static readonly EntryStatus BLOCKED = new EntryStatus("6");
public static readonly EntryStatus NO_CONTENT = new EntryStatus("7");
private EntryStatus(string name) : base(name) { }
}
The base class StringEnum is:
Edit: The StringEnum class is part of the Kaltura Generated API, should not change
public class StringEnum
{
private readonly string name;
protected StringEnum(string name)
{
this.name = name;
}
public override string ToString()
{
return name;
}
public static StringEnum Parse(Type type, string name)
{
FieldInfo[] fields = type.GetFields();
foreach (FieldInfo field in fields)
{
object val = field.GetValue(null);
if (val.GetType().BaseType == typeof(StringEnum))
{
if (val.ToString() == name)
return (StringEnum)val;
}
}
return null;
}
}
}
Please accept System.Reflection, EntryStatus class and StringEnum class as givens for the problem. Modifications to EntryStatus and StringEnum can be done with the keyword partial only. I am attempting to understand the Kaltura Generated API library these are part of. All of your help is greatly appreciated.
-- Update --
This is an update after the re-write of your question.
I'm not quite sure what to call what to call what you are looking for. Right now, I used "OtherName".
This solution assumes two things.
The Kaltura Generated API (that should not be modified) exists as source in your project
Names associated with your EntryStatus things are unique (or mostly unique).
Possible Solution:
Create a new file in your project named EntryStatus.partial.cs. Add the following code:
public sealed partial class EntryStatus
{
private Dictionary<string, string> _namesDictionary = null;
public string AsOtherName()
{
if (_namesDictionary == null)
{
var fields = this.GetType().GetFields(BindingFlags.Public | BindingFlags.Static);
_namesDictionary = new Dictionary<string, string>(fields.Length);
foreach (var field in fields)
{
var fieldValue = field.GetValue(null);
var fieldName = (fieldValue as EntryStatus).ToString();
_namesDictionary[fieldName] = field.Name;
}
}
return _namesDictionary[ToString()];
}
}
That acts to modify the EntryStatus definition, but without touching the existing code. If that's too intimate a relationship, you'd need to build a class that reflects over the EntryStatus class and builds that dictionary.
When it's all finished, EntryStatus.ERROR_CONVERTING.AsOtherName() returns "ERROR_CONVERTING".
Then again, what's the point of typing EntryStatus.ERROR_CONVERTING and having a whole lot of code only to come up with "ERROR_CONVERTING"
--- Old Answer ---
I'm not quite sure what you are trying to do, but this might help:
First, I changed your Parse function to be generic, and to include a TryParse method as well (trust me, you'll appreciate it). Your current Parse returns null on failure. The expectation of most users is that an exception is thrown will be thrown from a Parse method on failure.
The code below does what I think you are describing, but I'm pretty sure that it doesn't do what you want. See my suggested changes below for what I think you want.
The biggest change is that I changed your FieldInfo[] fields = type.GetFields(); to var fields = type.GetFields(BindingFlags.Public|BindingFlags.Static); Your EntryStatus class only has static members, and it's not instantiable by anyone outside itself (so it doesn't really matter).
The new Parse (and TryParse) code:
public static bool TryParse<T>(string name, out StringEnum stringEnum) where T : StringEnum
{
stringEnum = null;
var type = typeof(T);
var fields = type.GetFields(BindingFlags.Public|BindingFlags.Static);
foreach (var field in fields)
{
var val = field.GetValue(null);
if (val is StringEnum typedVal)
{
if (typedVal.ToString() == name)
{
stringEnum = typedVal;
return true;
}
}
}
return false;
}
and
public static StringEnum Parse<T>(string name) where T: StringEnum
{
if (StringEnum.TryParse<T>(name, out var val))
{
return val;
}
else
{
return null; //you should probably make this throw
}
}
With that, if I say this:
Debug.WriteLine(StringEnum.Parse<EntryStatus>("virusScan.Infected"));
I get
virusScan.Infected
So...
What I think you want instead is to change:
if (typedVal.ToString() == name) //in my TryParse method
to
if (field.Name == name)
Now, if you run StringEnum.Parse<EntryStatus>("SCAN_FAILURE") you will get:
virusScan.ScanFailure
Is that close to what you are talking about? If you want a better answer, you will need to remove most of what starts with the paragraph that starts with "I call the API" and replace it with text and code that makes up a Minimal Reproduceable Example. For example the code block immediately after the "I call the API" paragraph does not include StringEnum or EntryStatus. I really can't tell what you are talking about.
As a final note, you may want to include an implicit operator on your StringEnum class that allows implicit conversions to string. If you don't want implicit conversions, you should at least provide an explicit operator to allow casting to strings. See: User-defined Implicit and Explicit Conversion Operators
I suppose you want to model the KalturaEntryStatus and other similar enums. In my opinion is reflection a bit overkill here. So I propose another solution, which is based on a simple Dictionary<string, string> as also suggested by #Flydog57.
The sample contains only two enums with only 2 members:
/// <summary>
/// Contains the various return codes of Kaltura API functions.
/// </summary>
public class KalturaEnum
{
/// <summary>
/// Contains the return codes for function XXX.
/// </summary>
public static readonly KalturaEnum KalturaEntryStatus = new KalturaEnum(nameof(KalturaEntryStatus),
("-2", "Error importing"),
("-1", "Error converting")
);
/// <summary>
/// Contains the return codes for function YYY.
/// </summary>
public static readonly KalturaEnum KalturaBatchJobType = new KalturaEnum(nameof(KalturaBatchJobType),
("ReachInternal.ReachInternalQueueHandler", "Reach internal queue handler"),
("0", "Convert")
);
private readonly Dictionary<string, string> values;
private KalturaEnum(string enumName, params (string Code, string Description)[] values)
{
if (string.IsNullOrWhiteSpace(enumName))
throw new ArgumentException($"'{nameof(enumName)}' cannot be null or whitespace.", nameof(enumName));
EnumName = enumName;
this.values = values.ToDictionary(a => a.Code, a => a.Description, StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Gets the name of this enumeration (not really usefull...).
/// </summary>
public string EnumName { get; }
/// <summary>
/// Gets the description of a return code by using a case-insensitive search.
/// </summary>
/// <param name="code">The return code of a API function.</param>
/// <returns>The description for <paramref name="code"/> or "Unknown return value '<paramref name="code"/>' for the type <see cref="EnumName"/>."</returns>
public string GetDescription(string code) => code != null && values.TryGetValue(code, out var name) ? name : $"Unknown return value '{code ?? "null"}' for the type {EnumName}.";
}
Test and output:
Console.WriteLine(KalturaEnum.KalturaEntryStatus.GetDescription("-2"));
Console.WriteLine(KalturaEnum.KalturaBatchJobType.GetDescription("1"));
Error importing
Unknown return value '1' for the type KalturaBatchJobType.
In your code it would look like this:
foreach (MediaEntry MediaEntry in result.Objects)
{
Console.WriteLine(KalturaEnum.KalturaEntryStatus.GetDescription(MediaEntry.Status));
}
Related
I have stored immutable types in a temporary CQRS read store (query/read side, in fact implemented by a simple List with abstraction access layer, I don't want to use a full blown document database at this point). These read stores contains items like the following:
public class SomeItem
{
private readonly string name;
private readonly string description;
public SomeItem(string name, string description)
{
this.name = name;
this.description = description;
}
public string Name
{
get { return this.name; }
}
public string Description
{
get { return this.description; }
}
}
Now I want to change the Name and in a 2nd Command the Description.
These changes should keep the current state, which means for the example above:
// initial state
var someItem = new SomeItem("name", "description");
// update name -> newName
someItem = new SomeItem("newName", someItem.Description);
// update description -> newDescription
someItem = new SomeItem(someItem.Name, "newDescription");
This does look error prone to me if you have several properties... you have to manage keeping the current state. I could add something like Clone() to every type but I think/hope there is something better out there that performs well and is easy to use, I don't want to write much repetive code (lazy programmer). Any suggestions how to improve the code above? The SomeItem class needs to stay immutable (transported through several different threads).
Sadly, there's no simple way in C#. F# has the with keyword, and you could have a look at lenses, but it's all somewhat tedious in C#. The best I can give you is something like this:
class SomeItem
{
private readonly string name;
private readonly string description;
public SomeItem(string name, string description)
{
this.name = name;
this.description = description;
}
public SomeItem With
(
Option<string> name = null,
Option<string> description = null
)
{
return new SomeItem
(
name.GetValueOrDefault(this.name),
description.GetValueOrDefault(this.description)
);
}
}
This allows you to do the updates like
var newItem = oldItem.With(name: "My name!");
I've used this approach with extension methods and T4s to great effect, but even when you write the code manually, it's reasonably reliable - if you add a new field, you must add it to the With as well, so it works quite well.
There's a few more approaches if you are willing to tolerate runtime code generation and reducing type safety, but that's kind of going against the grain IMO.
With C#9 we got the with operator for this purpose.
public record Car
{
public string Brand { get; init; }
public string Color { get; init; }
}
var car = new Car{ Brand = "BMW", Color = "Red" };
var anotherCar = car with { Brand = "Tesla"};
With-expressions When working with immutable data, a common pattern is
to create new values from existing ones to represent a new state. For
instance, if our person were to change their last name we would
represent it as a new object that’s a copy of the old one, except with
a different last name. This technique is often referred to as
non-destructive mutation. Instead of representing the person over
time, the record represents the person’s state at a given time. To
help with this style of programming, records allow for a new kind of
expression; the with-expression:
News in C#9
NOTE
With operator is only supported by records.
Records At the core of classic object-oriented programming is the idea that an object has strong identity and encapsulates mutable state
that evolves over time. C# has always worked great for that, But
sometimes you want pretty much the exact opposite, and here C#’s
defaults have tended to get in the way, making things very laborious.
Recods in C#9
What you are looking for is commonly called the with operator:
// returns a new immutable object with just the single property changed
someItem = { someItem with Name = "newName" };
Unfortunately, unlike F#, C# does not have such an operator (yet?).
Other C# developers are missing this feature as well, which is why someone wrote a Fody extension to do exactly that:
https://github.com/mikhailshilkov/With.Fody
Here's another approach, which implements an UpdateWith method manually but requires an Option<T> helper class. Luaan's answer describes this approach in more detail:
Implementing F#-inspired "with" updates for immutable classes in C#
Simple solution
I also thought about this question. Record's are not suitable for my purposes, since it is necessary to interact with EF Core.
I suggest a simple and low-cost way:
add a copy constructor to the class;
Make properties that change during cloning available for initialization;
clone an object with a change through the copy constructor with an initialization list:
var a = new SomeItem("name", "abracadabra");
var b = new SomeItem(a) {Description="descr"};
Simple code
var a = new SomeItem("name", "abracadabra");
var b = new SomeItem(a) {Description="descr"};
public class SomeItem
{
private string name;
private string description;
public SomeItem(string name, string description)
{
Name = name;
Description = description;
}
public SomeItem(SomeItem another): this(another.Name, another.Description)
{
}
public string Name
{
get => name;
init => name = value;
}
public string Description
{
get => description;
init => description = value;
}
}
Extended solution
If the final type is not known at compile time, then this approach is easy to extend. Let's say there is a class "ValueObject" whose derived types we need to clone.
Note: I apologize for the incorrect translation in some places. English version obtained using google.translate
Additional code
using System.Linq.Expressions;
using Light.GuardClauses;
using JetBrains.Annotations;
using static DotNext.Linq.Expressions.ExpressionBuilder;
using ValueObject = Company.Domain....;
/// <summary>
/// The plagiarizer creates a copy of the object with a change in its individual properties using an initializer
/// </summary>
/// <remarks> The foreign object must define a copy constructor, and mutable members must support initialization </remarks>
public struct Plagiarist {
/// <summary>
/// Object to be copied
/// </summary>
private readonly object _alienObject;
/// <summary>
/// Type <see cref="_alienObject" />
/// </summary>
private Type _type => _alienObject.GetType();
/// <summary>
/// Object parsing Expression
/// </summary>
private readonly ParsingInitializationExpression _parser = new();
public Plagiarist(object alienObject) {
_alienObject = alienObject.MustNotBeNullReference();
if (!CopyConstructorIs())
throw new ArgumentException($"Type {_type.FullName} must implement a copy constructor");
}
/// <summary>
/// Does the object we want to plagiarize have a copy constructor?
/// </summary>
/// <returns>True - there is a copy constructor, otherwise - false</returns>
[Pure]
private bool CopyConstructorIs() {
return _type.GetConstructor(new[] { _type }) is not null;
}
/// <summary>
/// Returns a copy of a foreign object with a change in its individual properties using an initializer
/// </summary>
/// <param name="initializer">
/// <see cref="Expression" /> create an object with initialization of those fields,
/// which need to be changed:
/// <code>() => new T() {Member1 = "Changed value1", Member2 = "Changed value2"}</code>
/// or <see cref="Expression" /> create an anonymous type with initialization of those fields
/// that need to be changed:
/// <code>() => new {Member1 = "Changed value1", Member2 = "Changed value2"}</code>
/// </param>
/// <returns></returns>
[Pure]
public object Plagiarize(Expression<Func<object>> initializer) {
var (newValues, constructParam) = _parser.ParseInitialization(initializer);
var constrCopies = _type.New(_alienObject.Const().Convert(_type));
Expression plagiarist = (newValues.Count, constructParam.Count) switch {
(> 0, _) => Expression.MemberInit(constrCopies, newValues.Values),
(0, > 0) => Expression.MemberInit(constrCopies, ConstructorInInitializationList(constructParam).Values),
_ => constrCopies
};
var plagiarize = Expression.Lambda<Func<object>>(plagiarist).Compile();
return plagiarize();
}
[Pure]
public Dictionary<string, MemberAssignment> ConstructorInInitializationList(
Dictionary<string, Expression> constructorParameters) {
Dictionary<string, MemberAssignment> initializer = new();
const BindingFlags flagReflections = BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public;
var allProperties = _type.GetProperties(flagReflections);
var allFields = _type.GetFields(flagReflections);
foreach (var memberName in constructorParameters.Keys) {
var property = allProperties.FirstOrDefault(s => s.Name ==memberName);
var field = allFields.FirstOrDefault(s => s.Name == memberName);
(MemberInfo member, Type memberType) = (property, field) switch {
({ }, _) => (property, property.PropertyType),
(null, { }) => ((MemberInfo)field, field.FieldType),
_ => throw new ArgumentException($"{_type.FullName} does not contain member {memberName}")
};
initializer[memberName] = Expression.Bind(member, constructorParameters[memberName].Convert(memberType));
}
return initializer;
}
/// <summary>
/// Template "Visitor" for traversing the expression tree in order to highlight
/// initialization expression and constructor
/// </summary>
private class ParsingInitializationExpression : ExpressionVisitor {
private Dictionary<string, MemberAssignment>? _initializer;
private Dictionary<string, Expression>? _initializerAnonym;
/// <summary>
/// Parses the expression tree and returns the initializer and constructor parameters
/// </summary>
/// <param name="initializer"><see cref="Expression" /> to parse</param>
/// <returns> tuple of initializer and constructor</returns>
public ParsedInitialization ParseInitialization(Expression initializer) {
_initializer = new Dictionary<string, MemberAssignment>();
_initializerAnonym = new Dictionary<string, Expression>();
Visit(initializer);
return new ParsedInitialization(_initializer, _initializerAnonym);
}
protected override MemberAssignment VisitMemberAssignment(MemberAssignment node) {
_initializer![node.Member.Name] = node;
return base.VisitMemberAssignment(node);
}
protected override Expression VisitNew(NewExpression node) {
foreach (var (member, value) in node.Members?.Zip(node.Arguments) ??
Array.Empty<(MemberInfo First, Expression Second)>())
_initializerAnonym![member.Name] = value;
return base.VisitNew(node);
}
/// <summary>
/// Type to return values from method <see cref="ParseInitialization" />
/// </summary>
/// <param name="Initializer"></param>
/// <param name="ConstructorParameters"></param>
public record struct ParsedInitialization(Dictionary<string, MemberAssignment> Initializer,
Dictionary<string, Expression> ConstructorParameters);
}
}
public static class ValueObjectPlagiarizer{
/// <summary>
/// Creates a copy of the object with a change in its individual properties using an initializer
/// </summary>
/// <param name="alien">Object to be plagiarized</param>
/// <param name="initializer">
/// <see cref="Expression" /> creating an object of type <typeparamref name="T" />
/// with initialization of those fields that need to be changed:
/// <code>ob.Plagiarize(() => new T() {Member1 = "Changed value1", Member2 = "Changed value2"})</code>
/// or <see cref="Expression" /> create an anonymous type with initialization of those fields that need to be changed:
/// <code>ob.Plagiarize(() => new {Member1 = "Changed value1", Member2 = "Changed value2"})</code>
/// </param>
/// <returns>plagiarism of the object</returns>
public static object Plagiarize<T>(this ValueObject alien, Expression<Func<T>> initializer)
where T : class {
var bodyReduced = initializer.Convert<object>();
var initializerReduced = Expression.Lambda<Func<object>>(bodyReduced, initializer.Parameters);
return new Plagiarist(alien).Plagiarize(initializerReduced);
}
}
Usages
If SomeItem is a descendant of ValueObject
ValueObject a = new SomeItem("name", "abracadabra");
// via type constructor
var b = (SomeItem)a.Plagiarize(()=>new SomeItem(null){Description="descr"});
// anonymous type
var c = (SomeItem)a.Plagiarize(()=>new{Description="descr"});
b.Description.Should().Be("descr"); //true
c.Description.Should().Be("descr"); //true
If what you want to do is (as you commented) update the name of an existing object, a readonly property might be bad design.
Otherwise if its really a new object you want to create, you might want your class to implement some interface with a 'Dispose' method.
We are planning a pretty big application.
-We want to internationalize our application for 30 countries.
-In most countries 1 to 6 different brands are available.
-Each combination of a certain locale like 'de' and brand like 'XXX' might occur multiple times therefore we need another identifier to get something unique:
"locale_brand_siteorigin"
Therefore we have .resx file like:
Configurations.de.burgerking.px10.resx
The bold printed is the unique identifier.
During runtime we create a:
var rm = new ResourceManager("MyNamespace.Configurations.UniqueIdentifier",Assembly.GetExecuting());
Depending on our business logic we can create the above resourceManager.
Finally we will end up having 180+ resx files with all combinations of the unique identifier.
Do you know of a better way to do this kind of branding?
4 years ago someone asked this question, but none answered:
Industry standard for implementing application branding?
UPDATE
I also want to extend my question asking for a solution showing the benefits of using the cultureandregioninfobuilder class to create those many custom cultures.
https://msdn.microsoft.com/en-us/library/system.globalization.cultureandregioninfobuilder(v=vs.110).aspx
I wouldn't recommend using .resx files for such a huge project. When a website is translated in many different languages, usually a lot of people are involved in the copy management, translation etc. These people will not be able to edit the .resx files since they are technically embedded in the application code. This means that your developers will have to constantly update the resources every time there are changes... a real nightmare for everybody.
I recently build a database-driven system for the SumoSoft.Cms. All the strings can be managed through the Admin panel, while in the code you just use:
#CmsMethods.StringContent("ContentSection_Name", "Fallback_Value")
This Helper queries the Database looking for an entity of Type "ContentSection" which is structured more or less like this:
public class ContentSection
{
public string Name { get; set; }
public ICollection<ContentSectionLocalizedString> LocalizedStrings { get; set; }
}
Each LocalizedString contains a reference to a specific Country and a property "Content", so all the Helper does is to choose the one that matches the Current Culture of the Thread.
Expanding on #FrancescoLorenzetti84 answer, one way I've done it in the past to make it easier to maintain is to wrap the database retrieval in a ResourceString class so that you can do something like:
private static readonly ResourceString res = "The value";
and then refer to that in the code. Behind the scene, the ResourceString class does the work. Here is an example of that:
namespace ResString
{
public interface IResourceResolver
{
string Resolve(string key, string defaultValue);
}
public class ResourceString
{
public ResourceString(string value)
{
this.defaultValue = value;
GetOwner();
}
public string Value
{
get
{
if (!resolved)
Resolve();
return value;
}
}
public override string ToString()
{
return Value;
}
public static implicit operator string(ResourceString rhs)
{
return rhs.Value;
}
public static implicit operator ResourceString(string rhs)
{
return new ResourceString(rhs);
}
protected virtual void Resolve()
{
if (Resolver != null)
{
if (key == null)
key = GetKey();
value = Resolver.Resolve(key, defaultValue);
}
else
{
value = defaultValue;
}
resolved = true;
}
[MethodImpl(MethodImplOptions.NoInlining)]
protected virtual void GetOwner()
{
StackTrace trace = new StackTrace();
StackFrame frame = null;
int i = 1;
while (i < trace.FrameCount && (owner == null || typeof(ResourceString).IsAssignableFrom(owner)))
{
frame = trace.GetFrame(i);
MethodBase meth = frame.GetMethod();
owner = meth.DeclaringType;
i++;
}
}
protected virtual string GetKey()
{
string result = owner.FullName;
FieldInfo field = owner.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(f =>
typeof(ResourceString).IsAssignableFrom(f.FieldType) && f.GetValue(null) == this
).FirstOrDefault();
if (field != null)
result += "." + field.Name;
return result;
}
public static IResourceResolver Resolver { get; set; }
private string defaultValue;
private string value;
private bool resolved;
private string key;
private Type owner;
}
}
And an example program:
namespace ResString
{
class Program
{
/// <summary>
/// Description for the first resource.
/// </summary>
private static readonly ResourceString firstRes = "First";
/// <summary>
/// Description for the second resource.
/// </summary>
private static readonly ResourceString secondRes = "Second";
/// <summary>
/// Description for the format string.
/// </summary>
private static readonly ResourceString format = "{0} {1}";
static void Main(string[] args)
{
ResourceString.Resolver = new French();
Console.WriteLine(String.Format(format, firstRes, secondRes));
}
private class French : IResourceResolver
{
public string Resolve(string key, string defaultValue)
{
switch (key)
{
case "ResString.Program.firstRes":
return "Premier";
case "ResString.Program.secondRes":
return "Deuxième";
case "ResString.Program.format":
return "{1} {0}";
}
return defaultValue;
}
}
}
}
If you run that, it will output:
Deuxième Premier
Comment out the Resolver assignment and you will get:
First Second
Any where you would use a string in the UI, use a declared ResourceString instead.
Changing the resolver after the string values have been resolved will not alter their value as the values are retrieved only once. You will of course need to write a real resolver that pulls from a database.
What you will then need is a utility program to run through the compiled classes and pull out the ResourceString declarations and put the key and default values into a database or text file so they can be translated. This should also go through the generated help XML files for each assembly and pull the comment for the ResourceString declarations so the translator has some context to work with. The key declarations will also provide context as you can easily group resources by UI class.
Add this to a build script the make sure it is updated regularly.
You can use the same approach with images and the like.
There is a very easy trick which creates a dictionary-like structure where keys are types.
The structure acts like a Dictionary<Type, T?> where keys are Type objects and values are instances of the corresponding types.
This wonderful structure is as fast as just a variable or array since the "lookup" is only done once by the compiler/JITter and the proper value reference is compiled into your program.
public static class MyDict<T> {
public static T Value { get; set; }
}
You can work with that structure like this:
MyDict<string>.Value = MyDict<int>.Value.ToString();
The problem is that this "dictionary" is global. The only way to create different dictionaries is to create different classes.
How can create a similar (fastest "lookup", no boxing) non-static structure? (Without code generation.)
Simply said: I want to have multiple Dictionary<Type, object>-like objects without lookup costs, casting and boxing.
Here's an approach that extends the method described in the question:
public class TypeDict
{
public T Get<T>()
{
return MyDict<T>.Values[this];
}
public void Set<T>(T value)
{
MyDict<T>.Values[this] = value;
}
private static class MyDict<T>
{
public static Dictionary<TypeDict, T> Values { get; private set; }
static MyDict()
{
Values = new Dictionary<TypeDict, T>();
}
}
}
Now we can use the TypeDict like this:
void X()
{
var a = new TypeDict();
var b = new TypeDict();
a.Set<int>(1);
a.Set<double>(3.14);
a.Set("Hello, world!");
//Note that type inference allows us to omit the type argument
b.Set(10);
b.Set(31.4);
b.Set("Hello, world, times ten!");
Console.WriteLine(a.Get<int>());
Console.WriteLine(a.Get<double>());
Console.WriteLine(a.Get<string>());
Console.WriteLine();
Console.WriteLine(b.Get<int>());
Console.WriteLine(b.Get<double>());
Console.WriteLine(b.Get<string>());
}
Ark-kun is using generics to essentially generate unique types at compile time. With a generic type, any static members are unique to that specific closed generic type. This way it's processed as fast as a standard static member lookup.
The above usage is equivalent to something like this:
public static class MyDict_String
{
public static string Value { get; set; }
}
public static class MyDict_Int32
{
public static int Value { get; set; }
}
MyDict_String.Value = MyDict_Int32.Value.ToString();
AFAIK, types are "static" (in that you can't define more than one that way) so I don't know of a way to cheat around this and maintain the same performance of a statically compiled member lookup.
Your best bet otherwise (I think) is to create a generic instance type that wraps its own dictionary that uses System.Type for its keys and System.Object for its values to which you have to perform boxing/casting when inserting/retrieving values.
EDIT: Here's a simple implementation wrapping a dictionary:
public class MyTypedDict
{
private Dictionary<Type, object> Values = new Dictionary<Type, object>();
public T Get<T>()
{
object untypedValue;
if (Values.TryGetValue(typeof(T), out untypedValue))
return (T)untypedValue;
return default(T);
}
public void Set<T>(T value)
{
Values[typeof(T)] = value;
}
}
Thinking about it more, it might be possible to achieve a more property-like syntax using an ExpandoObject (http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx) through some tomfoolery, but I feel like this would be pretty abusive and I can only assume terribly prone to runtime errors. (plus it would afford you nothing at compile time)
EDITx2: If you really want to have different sets of values, you could nest it within another generic type:
public static class ValueSets<T>
{
public static class MyDict<U>
{
public static U Value { get; set; }
}
}
With usage like:
ValueSets<int>.MyDict<string>.Value = "Hello ";
ValueSets<bool>.MyDict<string>.Value = "World!";
string helloworld = ValueSets<int>.MyDict<string>.Value + ValueSets<bool>.MyDict<string>.Value;
Console.WriteLine(helloworld);//Hello World!
But then the initial type int and bool in this case become "magical" and without meaning, plus you would need to provide a unique type per distinct set of values you'd like to use. Plus you could not pass it around and modify as an instance variable, rather it'd be statically accessible (so long as you have access to use the type T). So perhaps you could declare minimally visible types that are named with meaning and use those:
internal class MyFirstWords {}
internal class MySecondWords {}
ValueSets<MyFirstWords>.MyDict<string>.Value = "Hello ";
ValueSets<MySecondWords>.MyDict<string>.Value = "World!";
string helloworld = ValueSets<MyFirstWords>.MyDict<string>.Value + ValueSets<MySecondWords>.MyDict<string>.Value;
Console.WriteLine(helloworld);//Hello World!
Regardless, I think this is quite wacky and I wouldn't recommend it.
A more complicated version. Don't know if it's closer:
Define a generic dictionary:
public class MyDictionary<T>
{
Dictionary<string, T> dict;
public MyDictionary()
{
dict = new Dictionary<string, T>();
}
public T this[string name]
{
get
{
if (dict.ContainsKey(name))
return dict[name];
else
return default(T);//or throw
}
set
{
dict[name] = value;
}
}
}
Then a repository to store those dictionaries:
public class MyRepository
{
List<object> repo;
public MyRepository()
{
repo = new List<object>();
}
public void Add<T>(string name, T value)
{
if (!repo.OfType<MyDictionary<T>>().Any())
repo.Add(new MyDictionary<T>());
var dict = repo.OfType<MyDictionary<T>>().FirstOrDefault();
dict[name] = value;
}
public T GetValue<T>(string name)
{
if (!repo.OfType<MyDictionary<T>>().Any())
return default(T);//or throw
else
{
var dict = repo.OfType<MyDictionary<T>>().FirstOrDefault();
return dict[name];
}
}
}
And finally you may use this repository:
MyRepository repo = new MyRepository();
repo.Add("A", 1);
repo.Add("B", 1);
int i = repo.GetValue<int>("A") + repo.GetValue<int>("B");
In this example, there is MyDictionary<T> boxing to object is left.
From the other side, if your are working with some certain types you may not use thie repository class at all. But utilize separate dictionaties.
MyDictionary<int> intDict = new MyDictionary<int>();
intDict["A"] = 1;
intDict["B"] = 2;
int i = intDict["A"] + intDict["B"];
However it's the same as working with
Dictionary<string, int> intDict = new Dictionary<string, int>();
So the MyRepository class may be edited to use Dictionary<string, T> instead of MyDictionary<T>.
#Konstantin's answer made me remember that there is actually a very fast lookup method - array indexing. This crude PoC code shows a variant of the required structure.
public class TypeDictionary {
static int _maxId = 0;
int _id;
static class Store<T>{
internal static List<T> Values = new List<T>();
}
public TypeDictionary() {
_id = _maxId++;
}
public T GetValue<T>() {
return Store<T>.Values[_id];
}
public void SetValue<T>(T value) {
while(Store<T>.Values.Count < _id) {
Store<T>.Values.Add(default(T));
}
Store<T>.Values[_id] = value;
}
}
This code can be used as follows:
var dict1 = new TypeDictionary();
dict1.SetValue("my string");
string result = dict1.GetValue<string>();
The problem with this solution is it's memory usage caused by the repository being not sparse. This also makes first time value setting more expensive.
Try this:
public class MyDictionary
{
List<object> values;
public MyDictionary()
{
values = new List<object>();
}
public T GetValue<T>()
{
return values.OfType<T>().FirstOrDefault();
}
public bool Add<T>(T value)
{
if (values.OfType<T>().Any())
return false;
else
{
values.Add(value);
return true;
}
}
}
and use it:
var md = new MyDictionary();
md.Add("!!!");
string s = md.GetValue<string>();
This class may store up to one value of type T. But there could corner cases with derived classes and interfaces I guess. You may check, if it suits your need, and probably modify it as you need, if it's close to what you need in general.
What you are looking for is impossible in C#. The language does not support a container that could store multiple objects of different types yet provides a look up method that does not involve casting, boxing or unboxing. You could accomplish something like this with macros in C++, or via a language like javascript where the structure of types can be changed at run-time.
The usage case you are describing fits quite closely with the purpose for which ConditionalWeakTable<TKey,TValue> was added to .NET 4.0. For the purpose you describe, you would include such a table in a static generic class, and then for every class object that's supposed to contain a reference to an item of a particular type you would store into that type's table a reference to object that's supposed to contain the item along with either a reference to the item, or else a reference to a simple item-holder object (note that entries in ConditionalWeakTable will evaporate when an object ceases to exist, but are otherwise immutable, so if you want a mutable association you'll need to create an object to hold it).
Building on #phoog's example with #supercat's suggestion
public class TypeDict
{
public T Get<T>() where T : class
{
T value;
InnerDict<T>.Values.TryGetValue(this, out value);
return value;
}
public void Set<T>(T value) where T : class
{
var cwt = InnerDict<T>.Values;
// lock+remove+add https://github.com/dotnet/coreclr/issues/4545
lock (cwt)
{
cwt.Remove(this);
cwt.Add(this, value);
}
}
private static class InnerDict<T> where T : class
{
public static ConditionalWeakTable<TypeDict, T> Values { get; private set; }
static InnerDict()
{
Values = new ConditionalWeakTable<TypeDict, T>();
}
}
}
I'm using reflection to iterate over all the members of a given type. This interaction must support inheritance, since most type will be extended as necessary.
I've just found out that the order in which types present themselves when iterating over GetMembers isn't really what I'd expect -- the types of the derived classes appear first, in their current order, and the types of the base classes later, again in their current order.
Source:
using System;
class Program
{
class SomeClass
{
public string First { get; set; }
public int Second;
}
class AnotherClass : SomeClass
{
public int Third { get; set; }
public string Fourth;
}
public static void Main()
{
var obj = new AnotherClass { First = "asd", Second = 10};
foreach (var member in obj.GetType().GetMembers())
{
Console.WriteLine(member.Name);
}
}
}
Output:
get_Third
set_Third
get_First
set_First
Equals
GetHashCode
GetType
ToString
.ctor
Third
First
Fourth
Second
You can check a run here.
I'd like to invert this situation, using reflection to get only types from the base class, then from the derived. Is there any way to do this?
Another question on the same line: when searching members, properties come first and fields second. Anyway to change this behavior as well, or the metadata created will always present in that order?
Thanks!
To access the base type use BaseType property.
To check if a member is declared in the same type, use DeclaringType property:
public static bool DeclaredInType(Type typeToCheck, MemberInfo member)
{
return typeToCheck.Equals(member.DeclaringType);
}
EDIT: you can sort by type by using LINQ:
public static MemberInfo[] SortMembers(IEnumerable<MemberInfo> members)
{
return members.OrderBy(m => m.GetType().Name)
.ToArray();
}
This is not exactly an answer to the OP (and I'm a bit late for that), but I'll just describe what I did, in the hopes someone may find it helpful.
I have a home-made program that serializes to XML. It is driven by a List of CopierField objects that I create that contain the data I need to expedite the serialization. Here is a much-redacted version of that class:
private class CopierField
{
// Name of the field or property and a reference to the declaring Type
public string MemberName;
public Type DeclaringType;
// Reference to the FieldInfo or PropertyInfo object for this field or property. One of
// these will be null and the other non-null.
public FieldInfo MemberInfoForField = null;
public PropertyInfo MemberInfoForProperty = null;
// Ordering of this field, as returned by Type.GetMembers(). This is only used while
// building the List<> of these objects for XML serialization
public int FieldOrder;
/// <summary>
/// Comparison method that can be used to sort a collection of CopierField objects so they
/// are in the order wanted for XML serialization. This ordering is dependent on the depth
/// of derivation, and when that is equal it maintains the original ordering.
/// </summary>
public static readonly Comparison<CopierField> CompareForXml =
delegate(CopierField a, CopierField b)
{
int aDepth = GetTypeDepth(a.DeclaringType);
int bDepth = GetTypeDepth(b.DeclaringType);
if (aDepth != bDepth)
return aDepth.CompareTo(bDepth);
return a.FieldOrder.CompareTo(b.FieldOrder);
};
/// <summary>
/// Method to determine the depth of derivation for a type.
/// </summary>
private static int GetTypeDepth(Type aType)
{
int i = 0;
while (aType.BaseType != null)
{
i++;
aType = aType.BaseType;
}
return i;
}
}
Before serializing an object type to XML the first time I create a List of these objects sorted in the order I want using a method somewhat like this, where the input is a List of the CopierField objects that is based on data from Type.GetMembers().
private static List<CopierField> CreateCopierFieldListForXml(List<CopierField> copierFields)
{
// Build the new list, and note the original ordering as created by Type.GetMembers()
List<CopierField> copierFieldsForXml = new List<CopierField>(copierFields.Count);
for (int listIndex = 0; listIndex < copierFields.Count; listIndex++)
{
CopierField copierField = copierFields[listIndex];
copierField.FieldOrder = listIndex;
copierFieldsForXml.Add(copierField);
}
// Sort the new list as wanted for XML serialization
copierFieldsForXml.Sort(CopierField.CompareForXml);
return copierFieldsForXml;
}
TL;DR
orderby typeof(T).Equals(mi.DeclaringType) ? 1 : -1
will push base memberInfo first, and keep the order defined in the class.
Full answer:
to achieve the same goal, and using the DeclaringType as suggested previously, I defined the following method:
public static IEnumerable<MemberInfo> GetAllFieldsAndPropertiesOfClass<T>()
{
return
from mi in typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
let ignoreAttr = (IgnoreSerializationAttribute)Attribute.GetCustomAttribute(mi, typeof(IgnoreSerializationAttribute))
where (mi.MemberType == MemberTypes.Field || mi.MemberType == MemberTypes.Property)
&& (ignoreAttr == null || ignoreAttr != null && !ignoreAttr.Ignore)
orderby typeof(T).Equals(mi.DeclaringType) ? 1 : -1
select mi;
}
In that method, I also defined a custom attribute to explicitely ignore some properties from the serialization:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class IgnoreSerializationAttribute : Attribute
{
public bool Ignore { get; private set; }
public IgnoreSerializationAttribute(bool ignore)
{
Ignore = ignore;
}
}
It is also possible to add an other custom Attribute to define the order, e.g.
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ColumnOrderAttribute : Attribute
{
public int Order { get; private set; }
public ColumnOrderAttribute(int order)
{
Order = order;
}
}
used as follow:
public static IEnumerable<MemberInfo> GetAllFieldsAndPropertiesOfClassOrdered<T>()
{
return
from mi in GetAllFieldsAndPropertiesOfClass<T>()
let orderAttr = (ColumnOrderAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnOrderAttribute))
orderby orderAttr == null ? int.MaxValue : orderAttr.Order, mi.Name
select mi;
}
I am using those methods to serialize list of objects using other objects to CSV files...
I'm making a server library in which the packet association is done by enum.
public enum ServerOperationCode : byte
{
LoginResponse = 0x00,
SelectionResponse = 0x01,
BlahBlahResponse = 0x02
}
public enum ClientOperationCode : byte
{
LoginRequest = 0x00,
SelectionRequest = 0x01,
BlahBlahRequest = 0x02
}
That works fine when you're working in your own project - you can compare which enum member is returned (i.e. if (packet.OperationCode == ClientOperationCode.LoginRequest)). However, since this is a class library, the user will have to define its own enum.
Therefore, I have two enums to add as "abstract" - ServerOperationCode and ClientOperationCode. I know it's not possible to implement abstract enums in C#. How would I go doing this?
I like to use static instances on my classes when I need to do this. It allows you to have some default values but also lets it be extensible through the usual means of inheritance and interface implementations:
public abstract class OperationCode
{
public byte Code { get; private set; }
public OperationCode(byte code)
{
Code = code;
}
}
public class ServerOperationCode : OperationCode
{
public static ServerOperationCode LoginResponse = new ServerOperationCode(0x00);
public static ServerOperationCode SelectionResponse = new ServerOperationCode(0x01);
public static ServerOperationCode BlahBlahResponse = new ServerOperationCode(0x02);
public ServerOperationCode(byte code) : base(code) { }
}
public class ClientOperationCode : OperationCode
{
public static ClientOperationCode LoginRequest = new ClientOperationCode(0x00);
public static ClientOperationCode SelectionRequest = new ClientOperationCode(0x01);
public static ClientOperationCode BlahBlahRequest = new ClientOperationCode(0x02);
public ClientOperationCode(byte code) : base(code) { }
}
assuming packet.OperationCode return a byte, you will likely have to implement an == operator for byte. put this code into your abstract OperationCode class.
public static bool operator ==(OperationCode a, OperationCode b)
{
return a.Code == b.Code;
}
public static bool operator !=(OperationCode a, OperationCode b)
{
return !(a == b);
}
this will allow you to have the same check as you showed:
if (packet.OperationCode == ClientOperationCode.LoginRequest)
Why does everyone think that Enums cannot be abstracted?
The class System.Enum IS the abstraction of an enumeration.
You can assign any enumeration value to an Enum, and you can cast it back to the original enumeration or use the name or value.
eg:
This little snippet of code is from a dynamic property collection used in one of my control libraries. I allow properties to be created and accessed through an enumeration value to make it slightly faster, and less human-error
/// <summary>
/// creates a new trigger property.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="name"></param>
/// <returns></returns>
protected virtual TriggerProperty<T> Create<T>(T value, Enum name)
{
var pt = new TriggerProperty<T>(value, OnPropertyChanged, Enum.GetName(name.GetType(), name));
_properties[name.GetHashCode()] = pt;
return pt;
}
I use Enum.GetName(Type, object) to get the name of the enumeration value (to supply a name for the property), and for speed and consistency reasons I use GetHashCode() to return the integer value of the enumeration member (the hash code for an int is always just the int value)
This is an example of the method being called:
public enum Props
{
A, B, C, Color, Type, Region, Centre, Angle
}
public SpecularProperties()
:base("SpecularProperties", null)
{
Create<double>(1, Props.A);
Create<double>(1, Props.B);
Create<double>(1, Props.C);
Create<Color>(Color.Gray, Props.Color);
Create<GradientType>(GradientType.Linear, Props.Type);
Create<RectangleF>(RectangleF.Empty, Props.Region);
Create<PointF>(PointF.Empty, Props.Centre);
Create<float>(0f, Props.Angle);
}
If you mean to say that you want an enum that can be extended by clients of the library, check out my CodeProject article on the topic, Symbols as extensible enums.
Note that in my library, Symbol chooses ID numbers for the "enum values" automatically, since it is designed for use inside a single program rather than for exchanging values on a network. Perhaps it would be possible, however, to alter Symbol.cs to your liking so that clients can assign constant values to symbols.
Create an Enum for LoginResponse, SelectionResponse, etc., but don't specify the values.
Have ServerOperationCode and ClientOperationCode implement a function that, given an integer bytecode, returns the appropriate value from your Enum.
Example:
public enum OperationCode
{
LoginResponse,
SelectionResponse,
BlahBlahResponse
}
public interface IOperationCodeTranslator {
public OperationCode GetOperationCode(byte inputcode);
}
public class ServerOperationCode : IOperationCodeTranslator
{
public OperationCode GetOperationCode(byte inputcode) {
switch(inputcode) {
case 0x00: return OperationCode.LoginResponse;
[...]
}
}
Caveat: since interfaces can't define static functions, ServerOperationCode and ClientOperationCode would only be able to implement a common interface if said function is an instance function. If they don't need to implement a common interface, GetOperationCode can be a static function.
(Apologies for any C# snafus, it's not my first language...)
If there is a database that is shared between your client and server application, then look-up tables may help; the table structure just contain an integer value (ID) and a string (the name), this table can be filled out by either side of your application (the client or the server) and read by the other. You can cache these table (in your code) in a dictionary for quick look-up.
You can also implement the same thing in the app.config file; force the user of your library to set these values in the app.config file which your library can access easily.
I wrote a message switching library with a similar scenario a while back, and I decided to use generics to pass the user-defined enum. The main problem with this is you can't constrain your generic to only enum types, but can only say while T: struct. Someone may instantiate your type with some other primitive type (although, using ints could still be functional, provided they're all unique values. The dictionary will throw an exception if they're not. You could possibly add some additional check using reflection to ensure you pass an enum.
public abstract class DefaultMessageHandler<T> : IMessageHandler<T> where T : struct {
public delegate void MessageHandlerDelegate(IMessage<T> message, IConnection connnection);
private readonly IDictionary<T, MessageHandlerDelegate> messageHandlerDictionary =
new Dictionary<T, MessageHandlerDelegate>();
protected void RegisterMessageHandler(T messageType, MessageHandlerDelegate handler) {
if (this.messageHandlerDictionary.ContainsKey(messageType))
return;
else this.messageHandlerDictionary.Add(messageType, handler);
}
protected void UnregisterMessageHandler(T messageType) {
if (this.messageHandlerDictionary.ContainsKey(messageType))
this.messageHandlerDictionary.Remove(messageType);
}
protected virtual void HandleUnregisteredMessage(IMessage<T> message, IConnection connection) {
}
void IMessageHandler<T>.HandleMessage(IMessage<T> message, IConnection connection) {
if (this.messageHandlerDictionary.ContainsKey(message.MessageType))
this.messageHandlerDictionary[message.MessageType].Invoke(message, connection);
else HandleUnregisteredMessage(message, connection);
}
}
Given your example scenario, you'd just subclass it like this.
public sealed class ServerOperationHandler : DefaultMessageHandler<ServerOperationCode> {
public ServerOperationHandler() {
this.RegisterMessageHandler(ServerOperationCode.LoginResponse, this.HandleLoginResponse);
this.RegisterMessageHandler(ServerOperationCode.SelectionResponse, this.HandleSelectionResponse);
}
private void HandleLoginResponse(IMessage<ServerOperationCode> message, IConnection connection) {
//TODO
}
private void HandleSelectionResponse(IMessage<ServerOperationCode> message, IConnection connection) {
//TODO
}
}
How about using static Dictionary and a virtual method to retrieve the static dictionaries in the inherited classes?
Like the follow for your case:
public abstract class Operation
{
protected abstract Dictionary<string, int> getCodeTable();
public int returnOpCode(string request){ return getCodeTable()[request]; }
}
public class ServerOperation : Operation
{
Dictionary<string, int> serverOpCodeTable = new Dictionary<string, int>()
{
{"LoginResponse", 0x00,},
{"SelectionResponse", 0x01},
{"BlahBlahResponse", 0x02}
};
protected override Dictionary<string, int> getCodeTable()
{
return serverOpCodeTable;
}
}
public class ClientOperation : Operation
{
Dictionary<string, int> cilentOpCodeTable = new Dictionary<string, int>()
{
{"LoginResponse", 0x00,},
{"SelectionResponse", 0x01},
{"BlahBlahResponse", 0x02}
};
protected override Dictionary<string, int> getCodeTable()
{
return cilentOpCodeTable;
}
}