How to do extreme branding/internationalization in .NET - c#

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.

Related

Kaltura API C# How to get Value of StringEnum

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

String Object with fixed length C#

I have a class wherein I want to use Strings with a fixed size.
The reason for the fixed size is that the class "serializes" into a textfile
with values with a fixed length. I want to avoid to write foreach value a guard clause and instead have the class handle this.
So I have round about 30 properties which would look like this
public String CompanyNumber
{
get
{
return m_CompanyNumber.PadLeft(5, ' ');
}
set
{
if (value.Length > 5)
{
throw new StringToLongException("The CompanyNumber may only have 5 characters", "CompanyNumber");
}
m_CompanyNumber = value;
}
}
I would like to have a String that handles this by itself. Currently I have the following:
public class FixedString
{
String m_FixedString;
public FixedString(String value)
{
if (value.Length > 5)
{
throw new StringToLongException("The FixedString value may consist of 5 characters", "value");
}
m_FixedString= value;
}
public static implicit operator FixedString(String value)
{
FixedString fsv = new FixedString(value);
return fsv;
}
public override string ToString()
{
return m_FixedString.PadLeft(5,' ');
}
}
The problem I have with this solution is that I can't set the String length at "compile time".
It would be ideal if it would look something like this in the end
public FixedString<5> CompanyNumber { get; set; }
I would go further back and question the design. This solution mashes together two concerns--internal application state and storage format--that should remain separate.
You could decorate each string property with a MaxLengthAttribute and then validate to that, but your code for (de)serializing from your storage format should be completely separate. It could use the same attributes to glean the field lengths for storage (if that happy coincidence holds) but your internal representation shouldn't "know" about the storage details.
Make FixedString take the size as a constructor parameter, but not the value itself
public class FixedString
{
private string value;
private int length;
public FixedString(int length)
{
this.length = length;
}
public string Value
{
get{ return value; }
set
{
if (value.Length > length)
{
throw new StringToLongException("The field may only have " + length + " characters");
}
this.value = value;
}
}
}
Initilise it with your class, and just set the Value when it changes
public class MyClass
{
private FixedString companyNumber = new FixedString(5);
public string CompanyNumber
{
get{ return companyNumber.Value; }
set{ companyNumber.Value = value; }
}
}
You can define an Interface like this:
public interface ILength
{
int Value { get; }
}
Some struct that implements the interface:
public struct LengthOf5 : ILength
{
public int Value { get { return 5; } }
}
public struct LengthOf10 : ILength
{
public int Value { get { return 10; } }
}
And then:
public class FixedString<T> where T : struct, ILength
{
String m_FixedString;
public FixedString(String value)
{
if (value.Length > default(T).Value)
{
throw new ArgumentException("The FixedString value may consist of " + default(T).Value + " characters", "value");
}
m_FixedString = value;
}
public static implicit operator FixedString<T>(String value)
{
FixedString<T> fsv = new FixedString<T>(value);
return fsv;
}
public override string ToString()
{
return m_FixedString;
}
}
To be honest I don't know if i like this solution but is the best I can think to solve your problem.
You could put an attribute over your String property and then validate all of them at some time (maybe a button click or something like that).
using System.ComponentModel.DataAnnotations;
public class MyObject
{
[StringLength(5)]
public String CompanyName { get; set; }
}
public void Save(MyObject myObject)
{
List<ValidationResult> results = new List<ValidationResult>();
ValidationContext context = new ValidationContext(myObject, null, null);
bool isValid = Validator.TryValidateObject(myObject, context, results);
if (!isValid)
{
foreach (ValidationResult result in results)
{
// Do something
}
}
}
More about DataAnnotations here.
I think your original idea of creating a string of fixed length is a very valid one, strictly modelling the domain of your system and using the type system to verify it is an idea that I find very appealing. Questions like this seem to come up very often within the F# community.
Unfortunately something like the type definition you suggested (FixedString<5>) is not possible in the context of .NET.
Some of the answers so far have talked about workarounds, alternatives or other ideas, I'd like to instead answer why you can't do what you originally requested in C#.
First of all, lets look at how you could do this in an arbitrary language:
Templates: You could do something like this in C++ using the template system. As Eric Lippert puts it in his article on the differences between generics and templates, "You can think of templates as a fancy-pants search-and-replace mechanism" (https://blogs.msdn.microsoft.com/ericlippert/2009/07/30/whats-the-difference-part-one-generics-are-not-templates/).
.NET generics are, in many ways, far simpler by comparison. Generic types are allow you to parametrise over types but not over values and open types are resolved at runtime whereas templates are an entirely compile time construct.
Dependent Types: A few languages support a feature called dependent types (https://en.wikipedia.org/wiki/Dependent_type). This allows you to define types that depend upon values. Many languages that support this feature are geared toward theorem proving rather than general purpose development.
Idris is perhaps unusual in being a general purpose language under active development (albeit a little known one) which does support this feature (see http://www.idris-lang.org/).
C#
C# does not support either of these features so, unfortunately, you can't solve this problem in a way that can be rigorously verified by the compiler.
I think there are plenty of good suggestions covered here for how you might implement something like this in C# but they all boil down to run-time verification.

Neo4j .NET Client Execute String Cypher Queries

Is it possible to execute CYPHER queries as just plain old strings using the Neo4j .NET Client or any other module?
For instance, if I want to add some nodes to my graph database and already had the statements assembled, is there a means to execute a string:
CREATE (n:Edit {name:"L-1154LX"});
I'm looking to batch process a list of CREATE CYPHER queries that have already be created.
Officially documented at https://github.com/Readify/Neo4jClient/wiki/cypher#manual-queries-highly-discouraged
However, this will be bad for performance, and risky for security.
It's bad for performance, because it will have to re-parse every query. You should use parameters, like in the example at https://github.com/Readify/Neo4jClient/wiki/cypher-examples#create-a-user This way, the query text remains consistent, and just the parameter varies, so you don't incur the query compilation cost on every call.
It's risky for security, because you can easily get the encoding wrong, and expose yourself to injection risks.
So, please don't run manual queries unless you really understand what you're doing. They're hidden on purpose.
I am writing a .NET application that enables the extraction of nodes and relationships from Excel spreadsheets so that they can be dynamically generated and loaded into neo4j (see translation / management object model below).
When I load them into neo4j via the neo4jclient I will not know what my nodes look like at run time; they can have any number of attributes and these could have any name and value. In the examples at https://github.com/Readify/Neo4jClient/wiki/cypher-examples it looks like I should have local classes to refer to for attribute names and values; but this will not work. Am I missing a trick here? parameterised queries? (even these examples expected a local, hard coded class).
public class Node
{
public string NodeType = "";
public List<Attribute> Attributes;
public List<Relationship> ParentRelationships;
public List<Relationship> ChildRelationships;
public Node(string nodeType)
{
NodeType = nodeType;
Attributes = new List<Attribute>();
ParentRelationships = new List<Relationship>();
ChildRelationships = new List<Relationship>();
}
public void AddAttribute(Attribute attribute)
{
//We are not allowing empty attributes
if(attribute.GetValue() != "")
this.Attributes.Add(attribute);
}
public string GetIdentifier()
{
foreach (Attribute a in Attributes)
{
if (a.IsIdentifier)
return a.GetValue();
}
return null;
}
public void AddParentRelationship(Relationship pr)
{
ParentRelationships.Add(pr);
}
public void AddChildRelationship(Relationship cr)
{
ChildRelationships.Add(cr);
}
public class Attribute
{
private string Name;
private string Value;
public bool IsIdentifier;
public Attribute(string name, string value, bool isIdentifier)
{
SetName(name);
SetValue(value);
IsIdentifier = isIdentifier;
}
public void SetName(string name)
{
Name = name.Trim();
}
public void SetValue(string value)
{
Value = value.Trim();
}
public string GetName()
{
return Name;
}
public string GetValue()
{
return Value;
}
}

What would be the best way to implement change tracking on an object

I have a class which contains 5 properties.
If any value is assingned to any of these fields, an another value (for example IsDIrty) would change to true.
public class Class1
{
bool IsDIrty {get;set;}
string Prop1 {get;set;}
string Prop2 {get;set;}
string Prop3 {get;set;}
string Prop4 {get;set;}
string Prop5 {get;set;}
}
To do this you can't really use automatic getter & setters, and you need to set IsDirty in each setter.
I generally have a "setProperty" generic method that takes a ref parameter, the property name and the new value.
I call this in the setter, allows a single point where I can set isDirty and raise Change notification events e.g.
protected bool SetProperty<T>(string name, ref T oldValue, T newValue) where T : System.IComparable<T>
{
if (oldValue == null || oldValue.CompareTo(newValue) != 0)
{
oldValue = newValue;
PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(name));
isDirty = true;
return true;
}
return false;
}
// For nullable types
protected void SetProperty<T>(string name, ref Nullable<T> oldValue, Nullable<T> newValue) where T : struct, System.IComparable<T>
{
if (oldValue.HasValue != newValue.HasValue || (newValue.HasValue && oldValue.Value.CompareTo(newValue.Value) != 0))
{
oldValue = newValue;
PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(name));
}
}
You can implement the IChangeTracking or IRevertibleChangeTracking interfaces, now included in .NET Standard 2.0.
Implementation is as follows:
IChangeTracking:
class Entity : IChangeTracking
{
string _FirstName;
public string FirstName
{
get => _FirstName;
set
{
if (_FirstName != value)
{
_FirstName = value;
IsChanged = true;
}
}
}
string _LastName;
public string LastName
{
get => _LastName;
set
{
if (_LastName != value)
{
_LastName = value;
IsChanged = true;
}
}
}
public bool IsChanged { get; private set; }
public void AcceptChanges() => IsChanged = false;
}
IRevertibleChangeTracking:
class Entity : IRevertibleChangeTracking
{
Dictionary<string, object> _Values = new Dictionary<string, object>();
string _FirstName;
public string FirstName
{
get => _FirstName;
set
{
if (_FirstName != value)
{
if (!_Values.ContainsKey(nameof(FirstName)))
_Values[nameof(FirstName)] = _FirstName;
_FirstName = value;
IsChanged = true;
}
}
}
string _LastName;
public string LastName
{
get => _LastName;
set
{
if (_LastName != value)
{
if (!_Values.ContainsKey(nameof(LastName)))
_Values[nameof(LastName)] = _LastName;
_LastName = value;
IsChanged = true;
}
}
}
public bool IsChanged { get; private set; }
public void RejectChanges()
{
foreach (var property in _Values)
GetType().GetRuntimeProperty(property.Key).SetValue(this, property.Value);
AcceptChanges();
}
public void AcceptChanges()
{
_Values.Clear();
IsChanged = false;
}
}
Another option, which I like the most, is to use a change tracking library, such as TrackerDog, that generates all the boilerplate code for you, while just need to provide POCO entities.
There are more ways to achieve this if you don't want to implement all the properties by hand.
One option is to use a weaving library, such as Fody.PropertyChanged and Fody.PropertyChanging, and handle the change methods to cache old values and track object state.
Another option is to have the object's graph stored as MD5 or some other hash, and reset it upon any change, you might be surprised, but if you don't expect zillion changes and if you request it only on demand, it can work really fast.
Here is an example implementation (Note: requires Json.NET and Fody/PropertyChanged:
[AddINotifyPropertyChangedInterface]
class Entity : IChangeTracking
{
public string UserName { get; set; }
public string LastName { get; set; }
public bool IsChanged { get; private set; }
string hash;
string GetHash()
{
if (hash == null)
using (var md5 = MD5.Create())
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
{
_JsonSerializer.Serialize(writer, this);
var hash = md5.ComputeHash(stream);
this.hash = Convert.ToBase64String(hash);
}
return hash;
}
string acceptedHash;
public void AcceptChanges() => acceptedHash = GetHash();
static readonly JsonSerializer _JsonSerializer = CreateSerializer();
static JsonSerializer CreateSerializer()
{
var serializer = new JsonSerializer();
serializer.Converters.Add(new EmptyStringConverter());
return serializer;
}
class EmptyStringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
=> objectType == typeof(string);
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
=> throw new NotSupportedException();
public override void WriteJson(JsonWriter writer,
object value,
JsonSerializer serializer)
{
if (value is string str && str.All(char.IsWhiteSpace))
value = null;
writer.WriteValue(value);
}
public override bool CanRead => false;
}
}
Dan's solution is perfect.
Another option to consider if you're going to have to do this on multiple classes (or maybe you want an external class to "listen" for changes to the properties):
Implement the INotifyPropertyChanged interface in an abstract class
Move the IsDirty property to your abstract class
Have Class1 and all other classes that require this functionality to extend your abstract class
Have all your setters fire the PropertyChanged event implemented by your abstract class, passing in their name to the event
In your base class, listen for the PropertyChanged event and set IsDirty to true when it fires
It's a bit of work initially to create the abstract class, but it's a better model for watching for data changes as any other class can see when IsDirty (or any other property) changes.
My base class for this looks like the following:
public abstract class BaseModel : INotifyPropertyChanged
{
/// <summary>
/// Initializes a new instance of the BaseModel class.
/// </summary>
protected BaseModel()
{
}
/// <summary>
/// Fired when a property in this class changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Triggers the property changed event for a specific property.
/// </summary>
/// <param name="propertyName">The name of the property that has changed.</param>
public void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Any other model then just extends BaseModel, and calls NotifyPropertyChanged in each setter.
Set IsDirty to true in all of your setters.
You might also consider making the setter for IsDirty private (or protected, if you may have child classes with additional properties). Otherwise you could have code outside of the class negating its internal mechanism for determining dirtiness.
If there are a very large number of such classes, all having that same pattern, and you frequently have to update their definitions, consider using code generation to automatically spit out the C# source files for all the classes, so that you don't have to manually maintain them. The input to the code generator would just be a simple text file format that you can easily parse, stating the names and types of the properties needed in each class.
If there are just a small number of them, or the definitions change very infrequently during your development process, then it's unlikely to be worth the effort, in which case you may as well maintain them by hand.
Update:
This is probably way over the top for a simple example, but it was fun to figure out!
In Visual Studio 2008, if you add a file called CodeGen.tt to your project and then paste this stuff into it, you'll have the makings of a code generation system:
<## template debug="false" hostspecific="true" language="C#v3.5" #>
<## output extension=".cs" #>
<## assembly name="System.Core" #>
<## import namespace="System.Linq" #>
<#
// You "declare" your classes here, as in these examples:
var src = #"
Foo: string Prop1,
int Prop2;
Bar: string FirstName,
string LastName,
int Age;
";
// Parse the source text into a model of anonymous types
Func<string, bool> notBlank = str => str.Trim() != string.Empty;
var classes = src.Split(';').Where(notBlank).Select(c => c.Split(':'))
.Select(c => new
{
Name = c.First().Trim(),
Properties = c.Skip(1).First().Split(',').Select(p => p.Split(' ').Where(notBlank))
.Select(p => new { Type = p.First(), Name = p.Skip(1).First() })
});
#>
// Do not edit this file by hand! It is auto-generated.
namespace Generated
{
<# foreach (var cls in classes) {#> class <#= cls.Name #>
{
public bool IsDirty { get; private set; }
<# foreach (var prop in cls.Properties) { #>
private <#= prop.Type #> _storage<#= prop.Name #>;
public <#= prop.Type #> <#= prop.Name #>
{
get { return _storage<#= prop.Name #>; }
set
{
IsDirty = true;
_storage<#= prop.Name #> = value;
}
} <# } #>
}
<# } #>
}
There's a simple string literal called src in which you declare the classes you need, in a simple format:
Foo: string Prop1,
int Prop2;
Bar: string FirstName,
string LastName,
int Age;
So you can easily add hundreds of similar declarations. Whenever you save your changes, Visual Studio will execute the template and produce CodeGen.cs as output, which contains the C# source for the classes, complete with the IsDirty logic.
You can change the template of what is produced by altering the last section, where it loops through the model and produces the code. If you've used ASP.NET, it's similar to that, except generating C# source instead of HTML.
Both Dan's and Andy Shellam's answers are my favorites.
In anyway, if you wanted to keep TRACK of you changes, like in a log or so, you might consider the use of a Dictionary that would add all of your property changes when they are notified to have changed. So, you could add the change into your Dictionary with a unique key, and keep track of your changes. Then, if you wish to Roolback in-memory the state of your object, you could this way.
EDIT
Here's what Bart de Smet uses to keep track on property changes throughout LINQ to AD. Once the changes have been committed to AD, he clears the Dictionary. So, when a property changes, because he implemented the INotifyPropertyChanged interface, when a property actually changed, he uses a Dictionary> as follows:
/// <summary>
/// Update catalog; keeps track of update entity instances.
/// </summary>
private Dictionary<object, HashSet<string>> updates
= new Dictionary<object, HashSet<string>>();
public void UpdateNotification(object sender, PropertyChangedEventArgs e)
{
T source = (T)sender;
if (!updates.ContainsKey(source))
updates.Add(source, new HashSet<string>());
updates[source].Add(e.PropertyName);
}
So, I guess that if Bart de Smet did that, this is somehow a practice to consider.
There are multiple ways for change tracking with their pros and cons. Here are some ideas:
Observer Pattern
In .NET, the most common approach is to implement INotifyPropertyChanged, INotifyPropertyChangeing, and/or IObservable (see also Introduction to Rx). Tipp: The easiest way to do this is to use ReactiveObject from the ReactiveUI library as base object.
Using this interfaces, you can track when a property is changing or has changed. So this is the best method to react to changes in „real-time“.
You can also implement a change tracker to keep track of everything for more complex scenarios. The change tracker might have a list of the changes—listing property names, values, and timestamps as needed—internally. You can than query this list for the information you need. Think of something like the EventSourcing pattern.
Serialization and Diff
If you want to see if an object has changed and what has changed, you could serialize the original version and the current version.
One version of this is to serialize to JSON and calculate an JSON Patch. You can use the JsonPatchDocument<T> class (see also JsonPatchDocument Class) for this. The diff will tell you what has changed. (see also this question)
Manually
Then there is also the method of having multiple properties to keep the original state and the current state, and maybe an boolean that tells you if the field has changed but was changed back to the original value later.
This is very easy to implement, but might not be the best approach when handling more complex scenarios.
Carefully consider the underlying purpose the object tracking is required? Suppose if it is something like other objects have to do something based on another object's state, then consider implementing the observer design pattern.
If its something small consider implementing the INotifyPropertyChanged interface.
This is something that is built into the BusinessBase class in Rocky Lhokta's CLSA framework, so you could always go and look at how it's done...
I know this is an old thread, but I think Enumerations will not work with Binary Worrier's solution. You will get a design-time error message that the enum property Type "cannot be used as type parameter 'T' in the generic type or method"..."SetProperty(string, ref T, T)'. There is no boxing conversion...".
I referenced this stackoverflow post to solve the issue with enumerations: C# boxing enum error with generics
To support enums, please use the perfect solution of Binary Worrier and add the code below.
I have added Enum support for my own (and it was a pain), I guess this is nice to add as well.
protected void SetEnumProperty<TEnum>(string name, ref TEnum oldEnumValue, TEnum newEnumValue) where TEnum : struct, IComparable, IFormattable, IConvertible
{
if (!(typeof(TEnum).IsEnum)) {
throw new ArgumentException("TEnum must be an enumerated type");
}
if (oldEnumValue.CompareTo(newEnumValue) != 0) {
oldEnumValue = newEnumValue;
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
_isChanged = true;
}
}
And implemented via:
Public Property CustomerTyper As CustomerTypeEnum
Get
Return _customerType
End Get
Set(value As ActivityActionByEnum)
SetEnumProperty("CustomerType", _customerType, value)
End Set
End Property
I know that it's been a while since you asked this. If you're still interested to keep your classes clean and simple without the need of deriving from base classes, I would suggest to use PropertyChanged.Fody that has an IsChanged Flag implemented
There actually is a way by checking the object fields.
I know this isn't the way that you wanted, you need an extra call to check it but you can use this Script:
using System.Reflection;
using System.Collections.Generic;
namespace Tracking
{
public static class Tracker
{
public static List<(string Key, (FieldInfo Info, object Value)[] Fields)> Items = new List<(string Key, (FieldInfo Info, object Value)[] Fields)>();
public static void Dispose(string Key)
{
for (int i = 0; i < Items.Count; i++)
{
if (Items[i].Key == Key)
{
Items.RemoveAt(i);
break;
}
}
}
public static bool? IsChanged(this object Value, string Key)
{
for (int i = 0; i < Items.Count; i++)
{
var Item = Items[i];
if (Item.Key == Key)
{
for (int j = 0; j < Item.Fields.Length; j++)
{
if (Item.Fields[j].Info.GetValue(Value) != Item.Fields[j].Value)
{
Item.Fields[j].Value = Item.Fields[j].Info.GetValue(Value);
return true;
}
}
return false;
}
}
var list = new List<(FieldInfo, object)>();
var Fields = Value.GetType().GetFields();
for (int i = 0; i < Fields.Length; i++)
{
list.Add((Fields[i], Fields[i].GetValue(Value)));
}
Items.Add((Key, list.ToArray()));
return null;
}
public static FieldInfo[] Track(this object Value, string Key)
{
for (int i = 0; i < Items.Count; i++)
{
var Item = Items[i];
if (Item.Key == Key)
{
var result = new List<FieldInfo>();
for (int j = 0; j < Item.Fields.Length; j++)
{
if (Item.Fields[j].Info.GetValue(Value) != Item.Fields[j].Value)
{
Item.Fields[j].Value = Item.Fields[j].Info.GetValue(Value);
result.Add(Item.Fields[j].Info);
}
}
if (result.Count > 0) { return result.ToArray(); }
}
}
var list = new List<(FieldInfo, object)>();
var Fields = Value.GetType().GetFields();
for (int i = 0; i < Fields.Length; i++)
{
list.Add((Fields[i], Fields[i].GetValue(Value)));
}
Items.Add((Key, list.ToArray()));
return null;
}
}
}

Is it possible to create static field on base class but affect like creating on child class?

I need to create base class like the following code.
public class ResourceBase
{
protected static IDictionary<string, XDocument> resources;
protected static IDictionary<string, XDocument> Resources
{
get
{
if (resources == null)
{
// cache XDocument instance in resources variable seperate by culture name.
// load resx file to XDocument
}
return resources;
}
}
protected static string GetString(string resourceKey)
{
return GetString(resourceKey, System.Threading.Thread.CurrentThread.CurrentUICulture.Name);
}
protected static string GetString(string resourceKey, string cultureName)
{
// get data from XDocument instance
var result = (
from rs in Resources
let node = rs.Value.Root.Elements(XName.Get("data")).SingleOrDefault<XElement>(x => x.Attribute(XName.Get("name")).Value == resourceKey)
where
(rs.Key == DEFAULT_CULTUREKEY || cultureName == rs.Key) &&
node != null
orderby cultureName == rs.Key descending
select node.Element(XName.Get("value"))
).FirstOrDefault<XElement>();
return result.Value;
}
}
Next, I create child class like the following code.
public class MainResource : ResourceBase
{
public static string AppName
{
return GetString("AppName");
}
}
public class OtherResource : ResourceBase
{
public static string OtherName
{
return GetString("OtherName");
}
}
I have some problem because resource variable in base class. All child classes use some Resource variable. So, they always use same cached XDocument instance. Do you have any idea for fixing my sourcecode?
PS. I found some Attribute like ContextStaticAttribute which indicates that the value of a static field is unique for a particular context. I think a particular context should be difference thread. So, I can't use it for solving this question.
Thanks,
Make the base class abstract and do not provide an implementation for Resources. Then the derived class can provide it's own resource to the base class GetString method.
This seems to be calling for a Singleton implementation. The reason for your base class is to share logic, correct? Instead of making everything static, implement the Singleton pattern so that each one of your child classes will have their own instance, all sharing the logic from your base class.
This will allow them to have independent caching while sharing behaviour logic.
Seems like you need to cache each time for your child classes. When you cache XDocument, you need to provide a key that is different across your child classes. You could add this to your Base class
abstract string ResourceName { get; };
protected static IDictionary<string, XDocument> Resources
{
get
{
if (resources == null)
{
//Cache the XDocument with a key based on ResourceName.
}
return resources;
}
}
And then your MainResource has
string ResourceName { get { return "AppName"; } }
public static string AppName
{
return GetString(ResourceName);
}
2.The easier solution for solving this problem by using method extension only.
Strongly-typed resource file
[ResourceInfo("~/Views/Home", "Index")]
public class IndexView
{
protected static IDictionary<string, XDocument> resources = new Dictionary<string, XDocument>();
public static string Title
{
get
{
return resources.GetString("Title");
}
}
}
Resource Helper file
public static class ResourceHelper
{
const string RESOURCE_EXTENSION = "resx";
const string DEFAULT_CULTUREKEY = "(default)";
public static string GetString(this IDictionary<string, XDocument> resource, string resourceKey)
{
return resource.GetString(resourceKey, System.Threading.Thread.CurrentThread.CurrentUICulture.Name);
}
public static string GetString(this IDictionary<string, XDocument> resource, string resourceKey, string cultureName)
{
if (resource.Count == 0)
resource.LoadResource();
// retrieve data
}
public static void LoadResource(this IDictionary<string, XDocument> resource)
{
// logic to load resource
}
I tested this logic with same test case like #solution1. But I found very interesting result. It can retrieves more than 120,000 operations/sec. So, It's my final answer because it's simply, clean and fast.
Thanks,
1.Solution for solving this problem by using static resources variable for caching all of resource depend on Type of child class.
public class ResourceBase
{
protected static IDictionary<Type, IDictionary<string, XDocument>> resources;
protected static IDictionary<string, XDocument> Resources
{
get
{
if (resources == null)
{
// cache XDocument instance in resources variable seperate by type and culture name.
// load resx file to XDocument
}
return resources;
}
}
}
By the way, this solution require Child class Type every time by using the following code when I get resource value. Moreover, I tested this solution about 10k - 100k rounds and It can retrieves data about 6,000 operations/sec.. So, I can't use this solution for real world application because every web request must retrieves more than 50 operations.
public static Type GetCallerType(Type baseClass, int skipFrames)
{
StackTrace trace = new StackTrace(skipFrames + 1, false);
Type callerType = null;
for (int i = 0; i < trace.FrameCount; ++i)
{
StackFrame frame = trace.GetFrame(i);
Type type = frame.GetMethod().DeclaringType;
if (type == baseClass || IsInheritFrom(type, baseClass))
{
callerType = type;
}
else
{
break;
}
}
if (callerType != baseClass)
return callerType;
else
return null;
}

Categories