I just want him to give me what has changed at the entrance. When I want to get the same value to the input of the select method, I want to get the same values in the action output, not the whole properties class WeatherForecast.
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string Summary { get; set; }
}
public void method(){
Select(d=>
{
d.Summary = "dasd";
d.TemperatureC = 25;
});}
private void Select(Action<WeatherForecast> func)
{
var result = new WeatherForecast();
func(result);
foreach (var item in result.GetType().GetProperties())
{
RaisePropertyChanged(item.Name);
}
var ss = func;
}
'''
That isn't a thing that you can do trivially, basically. There are three general approaches you could use here:
add change tracking to the WeatherForecast type, so it knows what has changed (usually with some kind of reset method to mark everything unchanged, and code in each setter to record individual properties as changed)
use an external change tracker which records the original state in a shapshot somehow, then later: compares that against the current value
if using an Expression-tree, interpret the proposed changes there - however: the C# compiler cannot interpret the code in the question as an Expression-tree (even though an Expression-tree of this can be generated)
Of these, IMO only the first is even remotely viable here unless you have a lot of spare time. Something like:
private int _dirtyFlags;
public void ResetAllChanges() => _dirtyFlags = 0;
private DateTime _date;
public DateTime Date
{
get => _date;
set
{
if (_date != value) _dirtyFlags |= 1 << 0;
_date = value;
}
}
// this name is a convention used by some tools; but this
// could also be IsDateChanged, for example
public bool ShouldSerializeDate() => (_dirtyFlags & (1 << 0)) != 0;
private int _temperatureC;
public int TemperatureC
{
get => _temperatureC;
set
{
if (_temperatureC != value) _dirtyFlags |= 1 << 1;
_temperatureC = value;
}
}
public bool ShouldSerializeTemperatureC() => (_dirtyFlags & (1 << 1)) != 0;
etc; this is clearly quite a lot of work, and doesn't generalize much.
Related
Say we work with this class:
public class UsefulClass
{
public string A { get; set; }
public string B { get; set; }
public int? C { get; set; }
public int? D { get; set; }
public decimal E { get; set; }
public decimal F { get; set; }
}
Let's consider the following instance:
UsefulClass z_objUsefulInstance = new UsefulClass()
{
A = null,
C = null,
E = 0
};
At this point, z_objUsefulInstance.A and C are null, E is 0, B, D and F have not been initialized.
Is there a way to tell, automatically, which properties of z_objUsefulInstance haven't been initialized and which ones have been initialized with null or 0?
EDIT: by popular demand, why I need this: to emulate a system of database access akin to EntityFramework. Right now all properties are a specific generic type, so it's rather easy to know which is null and which is Generic<T>.HasNullValue == true. But that generic type causes various issues and now we'd like to get rid of it, particularly as we have grown more conversant with Expressions.
Is there a way to tell, automatically, which properties of z_objUsefulInstance haven't been initialized and which ones have been initialized with null or 0?
You can't really know in ways that you can easily inspect at runtime what properties have been set unless you intercept the property setter and set some sort of flag. from a first-principals perspective that would resemble something like this:
public class UsefulClass
{
public string A { get => _a; set { _a = value; A_Set = true; } }
private string _a;
private bool A_Set = false;
public string B { get => _b; set { _b = value; B_Set = true; } }
private string _b;
private bool B_Set = false;
public int? C { get => _c; set { _c = value; C_Set = true; } }
private string _c;
private bool C_Set = false;
public int? D { get => _d; set { _d = value; D_Set = true; } }
private string _d;
private bool D_Set = false;
public decimal E { get => _e; set { _e = value; E_Set = true; } }
private string _e;
private bool E_Set = false;
public decimal F { get => _f; set { _f = value; F_Set = true; } }
private string _f;
private bool F_Set = false;
}
It is pretty verbose, but you can see here how we are not comparing the value at all, we can determine definitively if each property has been set, thought not specifically during the initialization of the instance, this simple code only tracks if each property was set at all.
So after your init, we can inspect these new flags:
UsefulClass z_objUsefulInstance = new UsefulClass()
{
A = null,
C = null,
E = 0
};
Console.WriteLine(z.C_Set); // True
Console.WriteLine(z.D_Set); // False
We can simplify this with a dictionary for the backing store and helper methods to get and set the property values, we can even encapsulate that logic in a base class to make this easier to consume:
public class UsefulClass : PropertyTracker
{
public string A { get => GetProperty<string>(); set => SetProperty(value); }
public string B { get => GetProperty<string>(); set => SetProperty(value); }
public int? C { get => GetProperty<int?>(); set => SetProperty(value); }
public int? D { get => GetProperty<int?>(); set => SetProperty(value); }
public decimal E { get => GetProperty<decimal>(); set => SetProperty(value); }
public decimal F { get => GetProperty<decimal>(); set => SetProperty(value); }
}
public abstract class PropertyTracker
{
private Dictionary<string, object> _values = new Dictionary<string, object>();
protected void SetProperty<T>(T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
_values[propertyName] = value;
}
protected T GetProperty<T>([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
if (!_values.ContainsKey(propertyName))
return default;
return (T)_values[propertyName];
}
public bool IsSet(string propertyName)
{
return _values.ContainsKey(propertyName);
}
}
See we still have the concept of a backing store, it's just not a field anymore. The inspection code is a bit different too:
UsefulClass z_objUsefulInstance = new UsefulClass()
{
A = null,
C = null,
E = 0
};
Console.WriteLine(z.IsSet(nameof(UsefulClass.C)); // True
Console.WriteLine(z.IsSet(nameof(UsefulClass.D)); // False
There are all sorts of techniques you can use to scaffold this or similar code out across your classes, this is just an example implementation. You could even write a generic wrapper that uses reflection to do the same thing. In my solutions I tend to use T4 templates to generate what are effectively View Model classes. My main argument was that I could generate some verbose code and take a hit at compile-time instead of a performance hit at runtime with a reflection based implementation.
If your ViewModel classes inherit from your model class, then you can get close to an apparently automatic implementation that is more compatible with the rest of your runtime, but that would require your properties be declared as virtual to enable the inheriting class to override the implementation.
If you end up going down this route, consider adding value to your classes by implementing INotifyPropertyChanged, or perhaps IChangeTracking or IRevertibleChangeTracking while you're there.
UsefulClass z_objUsefulInstance = new UsefulClass() {
A = null
C = null,
E = 0
};
At this point, z_objUsefulInstance.A and C are null, E is 0,
B, D and F have not been initialized.
No that's not quite right.
From "14.11.4 Constructor Execution" in the C#7 language spec
Variable initializers are transformed into assignment statements, and these assignment statements are executed before the invocation of the base class instance constructor.
So before your instance constructor in the above example is started executing, the properties are assigned
A = default(string); // null
B = default(string); // null
C = default(int?); // null
D = default(int?); // null
E = default(decimal); // 0.0m
F = default(decimal); // 0.0m
(Not quite accurate, but close enough for this answer)
Then your instance constructor is run (in this example, the default provided by the compiler), then your property assignments are made
A = null,
C = null,
E = 0
. There's no difference between E = 0 and E = default(decimal), nor is there a difference between null and null (default(string)).
If you need to tell whether a property was set or not you will have to provide a backing field, or otherwise control access to the property.
If you want to read more about constructor details, a friendlier summary than the language spec can be found at https://jonskeet.uk/csharp/constructors.html .
I know, the title is bad, but I couldn't think if a better one. The question is very specific.
Ok, so I'm using a class in my game identical to Odin Inspector's example RPG Skills classes. But it's set up in a way I don't quite understand and I can't work out how to set the value (I can get it, and there is a setter, so it's possible to set too). Also, all the skill classes/structs/etc are in the same .cs file.
The SkillList function I use to get the Value:
(I get it with skills[Strength].Value; in other classes)
public int this[SkillType type]
{
get
{
for (int i = 0; i < this.skills.Count; i++)
{
if (this.skills[i].Type == type)
return this.skills[i].Value;
}
return 0;
}
set
{
for (int i = 0; i < this.skills.Count; i++)
{
if (this.skills[i].Type == type)
{
var val = this.skills[i];
val.Value = value;
this.skills[i] = val;
return;
}
}
this.skills.Add(new SkillValue(type, value));
}
}
SkillValue struct:
[Serializable]
public struct SkillValue : IEquatable<SkillValue>
{
public SkillType Type;
public int Value;
public SkillValue(SkillType type, int value)
{
this.Type = type;
this.Value = value;
}
public SkillValue(SkillType type)
{
this.Type = type;
this.Value = 0;
}
public bool Equals(SkillValue other)
{ return this.Type == other.Type && this.Value == other.Value; }
}
SkillType enum:
public enum SkillType
{
Science,
Technology,
Arts,
Language,
}
I've tried:
skills[Science].Value = 10;
skills[Science] = new SkillValue(Science, 10);
skills[Science, 10]; (using a new function made by me)
skills[Science](10);
skills[Science].Value(10);
skills[Science] = 10;
But none work, and I'm just guessing randomly now.
How can I set the value?
Thanks
The solution:
character.skills[Rorschach.Character.Skills.SkillType.Science] = value;
Your property is of type int and expects a key of type SkillType so it should probably be
SkillList skills;
skills[SkillType.Science] = 10;
actually also
I get it with skills[Strength].Value;
seems odd with the code you provided. As said the property returns an int which has no property Value so it should actually be
int x = skills[SkillType.Strength];
Now knowing the full implementation code and your actual usage:
public SkillList skills;
...
public int Science
{
get { return this.Character.skills[Science].Value; }
set { this.Character.skills[Science].Value(10); }
}
ATTENTION!
What you did here by accident is using the other property
public SkillValue this[int index]
{
get { return this.skills[index]; }
set { this.skills[index] = value; }
}
which takes an int index and returns a SkillValue.
BUT you are causing a runtime StackOverlowExeption due to a recursive call of Science.
You can't use Science inside of the getter or setter of equally called property!
Imagine using the getter as example:
You would call
var test = Science;
so it executes the getter
return Character.skills[Science].Value;
but well ... in order to know the value of Science in order to use it here as the index it would again have to execute the getter so again
return Character.skills[Science].Value;
and by now you hopefully get what I mean.
Solution
You property should actually as guessed before rather look like
public int Science
{
get { return Character.skills[SkillType.Science]; }
set { Character.skills[SkillType.Science] = value; }
}
I have Sprache set up to parse an Equation that has a number of different possible method calls in it. After it resolves the method, is there a way to determine the index values within the original string? Perhaps the Parse has a "current index" value and "length" value that's somehow accessible?
Example input string:
IndexOf("fred", 2) + IndexOf("bob")
using a parser like this...
Parser<Expression> FunctionCall = from namePart in Parse.Letter.Many().Text()
from lparen in Parse.Char('(')
from expr in Parameter.DelimitedBy(ListDelimiter)
from rparen in Parse.Char(')')
select CallMethod(namePart, Enumerable.Repeat(sourceData, 1)
.Concat(expr)
.ToArray());
Can anyone think of a "trick" that would allow me to determine that the first CallMethod handles SubString(0, 18), and the second CallMethod handles SubString(21, 14) from the original string?
If you use a generic class and extension method you can make a more general approach
public class PositionAware<T> : IPositionAware<PositionAware<T>>
{
public PositionAware(T value)
{
Value = value;
}
public T Value { get; }
public Position Start { get; private set; }
public int Length { get; private set; }
public PositionAware<T> SetPos(Position startPos, int length)
{
Start = startPos;
Length = length;
return this;
}
}
public static Parser<PositionAware<T>> WithPosition<T>(this Parser<T> value)
{
return value.Select(x => new PositionAware<T>(x)).Positioned();
}
Using it:
from c in Parse.Char('a').WithPosition()
select (c.Start, c.Value)
from c in Parameter.DelimitedBy(ListDelimiter).WithPosition()
select (c.Start, c.Value)
I've managed to answer my own question. It's the Positioned() parser extension call that allows a parser to track the position within the original text.
Parser<Expression> FunctionCall = (from namePart in Parse.Letter.Many().Text()
from lparen in Parse.Char('(')
from expr in Parameter.DelimitedBy(ListDelimiter)
from rparen in Parse.Char(')')
select new MethodPosAware(namePart, expr)).Positioned()
.Select(x => CallMethod(x.Value, Enumerable.Repeat(sourceData, 1)
.Concat(x.Params)
.ToArray(),
x.Pos.Pos, x.Length));
I had to make a new MethodPosAware class to keep the position information, that derives from Sprache's IPositionAware:
class MethodPosAware : IPositionAware<MethodPosAware>
{
public MethodPosAware(string methodName, IEnumerable<Expression> parameters)
{
Value = methodName;
Params = parameters;
}
public MethodPosAware SetPos(Position startPos, int length)
{
Pos = startPos;
Length = length;
return this;
}
public Position Pos { get; set; }
public int Length { get; set; }
public string Value { get; set; }
public IEnumerable<Expression> Params { get; set; }
}
I think I'll be extending this further to work with more than just Method names, but this is sufficient to answer my question for now. I hope this helps someone down the road.
lets say I have a custom class:
public class WineCellar
{
public string year;
public string wine;
public double nrbottles;
}
Lets say I now have a List of this custom class:
List<WineCellar> orignialwinecellar = List<WineCellar>();
containing these items:
2012 Chianti 12
2011 Chianti 6
2012 Chardonay 12
2011 Chardonay 6
I know that if I want to compare two list and return a new list that has only items that are not in the other list I would do:
var newlist = list1.Except(list2);
How can I extend this to a custom class? Lets say I have:
string[] exceptionwinelist = {"Chardonay", "Riesling"};
I would like this to be returned:
List<WineCellar> result = originalwinecellar.wine.Except(exceptionwinelist);
This pseudocode obviously doesnt work but hopefully illustrates what I m trying to do. This shoudl then return a List of the custom class winecellar with following items:
2012 Chianti 12
2011 Chianti 6
Thanks.
You don't really want to use Except here, as you don't have a collection of WineCellar objects to use as a blacklist. What you have is a collection of rules: "I don't want objects with such and such wine names".
Therefore it's better to simply use Where:
List<WineCellar> result = originalwinecellar
.Where(w => !exceptionwinelist.Contains(w.wine))
.ToList();
In human-readable form:
I want all WineCellars where the wine name is not present in the list of exceptions.
As an aside, the WineCellar class name is a bit misleading; those objects are not cellars, they are inventory items.
One solution is with an extension method:
public static class WineCellarExtensions
{
public static IEnumerable<WineCellar> Except(this List<WineCellar> cellar, IEnumerable<string> wines)
{
foreach (var wineCellar in cellar)
{
if (!wines.Contains(wineCellar.wine))
{
yield return wineCellar;
}
}
}
}
And then use it like this:
List<WineCellar> result = originalwinecellar.Except(exceptionwinelist).ToList();
exceptionWineList is a string[] but originalWineCellar is a List<WineCellar>, WineCellar is not a string, so it does not make sense to perform an Except between these.
You could just as easily do,
// use HashSet for look up performance.
var exceptionWineSet = new HashSet<string>(exceptionWineList);
var result = orginalWineCellar.Where(w => !exceptionWineSet.Contains(w.Wine));
What I think you are alluding to in your question is something like
WineCellar : IEquatable<string>
{
...
public bool Equals(string other)
{
return other.Equals(this.wine, StringComparison.Ordinal);
}
}
which allows you to equate WineCellars to strings.
However, if I were to rework your model I'd come up with something like,
enum WineColour
{
Red,
White,
Rose
}
enum WineRegion
{
Bordeaux,
Rioja,
Alsace,
...
}
enum GrapeVariety
{
Cabernet Sauvignon,
Merlot,
Ugni Blanc,
Carmenere,
...
}
class Wine
{
public string Name { get; set; }
public string Vineyard { get; set; }
public WineColour Colour { get; set; }
public WineRegion Region { get; set; }
public GrapeVariety Variety { get; set; }
}
class WineBottle
{
public Wine Contents { get; set; }
public int Millilitres { get; set; }
public int? vintage { get; set; }
}
class Bin : WineBottle
{
int Number { get; set; }
int Quantity { get; set; }
}
class Cellar : ICollection<WineBottle>
{
...
}
Then, you can see that there are several ways to compare Wine and I may want to filter a Cellar on one or more of Wine's properties. Therefore I might be temtpted to give myself some flexibility,
class WineComparer : EqualityComparer<Wine>
{
[Flags]
public Enum WineComparison
{
Name = 1,
Vineyard= 2,
Colour = 4,
Region = 8,
Variety = 16,
All = 31
}
private readonly WineComparison comparison;
public WineComparer()
: this WineComparer(WineComparison.All)
{
}
public WineComparer(WineComparison comparison)
{
this.comparison = comparison;
}
public override bool Equals(Wine x, Wine y)
{
if ((this.comparison & WineComparison.Name) != 0
&& !x.Name.Equals(y.Name))
{
return false;
}
if ((this.comparison & WineComparison.Vineyard) != 0
&& !x.Vineyard.Equals(y.Vineyard))
{
return false;
}
if ((this.comparison & WineComparison.Region) != 0
&& !x.Region.Equals(y.Region))
{
return false;
}
if ((this.comparison & WineComparison.Colour) != 0
&& !x.Colour.Equals(y.Colour))
{
return false;
}
if ((this.comparison & WineComparison.Variety) != 0
&& !x.Variety.Equals(y.Variety))
{
return false;
}
return true;
}
public override bool GetHashCode(Wine obj)
{
var code = 0;
if ((this.comparison & WineComparison.Name) != 0)
{
code = obj.Name.GetHashCode();
}
if ((this.comparison & WineComparison.Vineyard) != 0)
{
code = (code * 17) + obj.Vineyard.GetHashCode();
}
if ((this.comparison & WineComparison.Region) != 0)
{
code = (code * 17) + obj.Region.GetHashCode();
}
if ((this.comparison & WineComparison.Colour) != 0)
{
code = (code * 17) + obj.Colour.GetHashCode();
}
if ((this.comparison & WineComparison.Variety) != 0)
{
code = (code * 17) + obj.Variety.GetHashCode();
}
return code;
}
}
this probably looks like a lot of effort but it has some use. Lets say we wanted all the wine except the Red Rioja in your cellar, you could do something like,
var comparison = new WineComparer(
WineComparison.Colour + WineComparison.Region);
var exception = new Wine { Colour = WineColour.Red, Region = WineRegion.Rioja };
var allButRedRioja = cellar.Where(c =>
!comparison.Equals(c.Wine, exception));
I had this exact same issue to. I tried the example from Darren but couldn't get that to work properly.
I therefore made a modification from DarrenĀ“s example as follows:
static class Helper
{
public static IEnumerable<Product> Except(this List<Product> x, List<Product> y)
{
foreach(var xi in x)
{
bool found = false;
foreach (var yi in y) { if(xi.Name == yi.Name) { found = true; } }
if(!found) { yield return xi; }
}
}
}
This works for me. You can possibly add several fields in the if clause if needed.
To directly use such extension methods with generic classes you should implement comparator. It consists of two methods: Equal and GetHashCode. You should implement them in your WineCellar class.
Note the second example.
Note that the hash-based methods are much faster than basic 'List.Contains...' implementations.
I have the following class:
public class VendorClass {
public int VendorID { get; set; }
public string VendorName { get; set; }
}
The fields above match fields in the database table.
In the case of say VendorName, how do I give it a field width ?
VendorName maps to a field in the database which is varchar(15)
You can't limit the length of the string but you can use properties with backing fields to achieve the desired result :
public class VendorClass
{
public int VendorID { get; set; }
private string _vendorName;
public string VendorName
{
get { return _vendorName; }
set
{
if (value.Length > 15)
{
_vendorName = value.Substring(0,15);
} else {
_vendorName = value;
}
}
}
}
Strings in C# have almost-arbitrary length.
When loading from your database, it will automatically accommodate the actual string length. When saving to the database, your business logic, data layer or ORM (as appropriate) will need to ensure the proper maximum length.
A string can't have a set length in C#. You will have to handle the db length through some other mechanism like validation. Can't really tell you more without more details.
I would question why you would do this in c# code. However this link has a couple of ways around this. I suppose either truncation or taking a subsring is the best option. You could also make sure that the UI (or the model-view) takes care of details such as this.
I am not sure exactly what you are asking, but if you want to know the maximum length of a string, this question can help you.
If you want to limit the number of characters entered, I would suggest that you use server-side validation and/or client-side validation.
I just met a problem like what you described and found a way to create a limited length's string. Maybe a little inflexible but concise when there are only finite varchar length definitions in database.
Firstly introduce some basic classes:
public class Length16
{
public static int StringLength { get => 16; }
}
public class Length8
{
public static int StringLength { get => 8; }
}
public class Length15
{
public static int StringLength { get => 15; }
}
public class LimitedLengthString<T>
{
private string _sValue;
public LimitedLengthString(string sNewValue)
{
_sValue = sNewValue;
}
public static implicit operator LimitedLengthString<T>(string sNewValue)
{
var prop = typeof(T).GetProperty("StringLength");
int iLength = (int)prop.GetValue(null);
if (sNewValue.Length > iLength)
{
throw new Exception($"New string is too long! Allowed length {iLength}.");
}
return new LimitedLengthString<T>(sNewValue);
}
public static implicit operator string(LimitedLengthString<T> sSource)
{
return sSource.ToString();
}
public override string ToString()
{
return _sValue;
}
}
public class AutoTruncatedString<T>
{
private string _sValue;
public AutoTruncatedString(string sNewValue)
{
_sValue = sNewValue;
}
public static implicit operator AutoTruncatedString<T>(string sNewValue)
{
var prop = typeof(T).GetProperty("StringLength");
int iLength = (int)prop.GetValue(null);
return new AutoTruncatedString<T>(sNewValue.Substring(0, iLength));
}
public static implicit operator string(AutoTruncatedString<T> sSource)
{
return sSource.ToString();
}
public override string ToString()
{
return _sValue;
}
}
Use them like this:
LimitedLengthString<Length8> sLimitedLength8;
sLimitedLength8 = "asdfgasdfg"; // will error out
AutoTruncatedString<Length8> sAutoTruncated8;
sAutoTruncated8 = "asdfgasdfg"; // will be truncated
sLimitedLength8 will throw an error if you try to assign a string longer than 8 and sAutoTruncated8 will truncate the string you assign to it.
For you, you can define the VendorName this way:
public LimitedLengthString<Length15> VendorName { get; set; }
Hope this could help you.