I played around with the ValueTuple structure and tried to implement an immutable composite key. The key is composed of value types.
I tried to break the following implementation with some unit tests, so far without success. Am I missing something?
Also this is just out of curiosity, I want to get to ValueTuples and it's limitations before the release of .NET 4.7.
So far my understanding of a ValueTuple is that it is only mutable as a variable but not as a field or property. Not sure what "mutable" means here though. Does altering a ValueTuple instance actually create a new ValueTuple (like it's common knowledge that strings are "immutable" but actually reference types)?
from this answer
System.ValueTuple isn't only a struct, it's a mutable one, and one has to be careful when using them as such. Think what happens when a class holds a System.ValueTuple as a field.
Here my implementation and tests
public interface IHaveCompositeKey
{
(Guid id, string name) Key { get; }
}
public class ImmutableKey : IHaveCompositeKey
{
public (Guid id, string name) Key { get; }
public ImmutableKey((Guid id, string name) key) => Key = key;
public override int GetHashCode() => Key.GetHashCode();
public override bool Equals(object obj)
{
var a = obj as ImmutableKey;
return a != null && Key.Equals(a.Key);
}
}
[TestFixture]
public class KeyTests
{
[Test]
public void Test1() // passes
{
var key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
var b = new ImmutableKey(key);
Assert.IsTrue(a.Equals(b));
Assert.IsTrue(a.GetHashCode().Equals(b.GetHashCode()));
}
[Test]
public void Test2() // passes
{
(Guid id, string name) key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
key.name = "Bar"; // mutable
var b = new ImmutableKey(key);
Assert.IsFalse(a.Equals(b));
Assert.IsFalse(a.GetHashCode().Equals(b.GetHashCode()));
}
[Test]
public void Test3() // does not compile
{
var key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
// compilation error
a.Key.name = "Bar"; // immutable
var b = new ImmutableKey(a.Key);
Assert.IsFalse(a.Equals(b));
Assert.IsFalse(a.GetHashCode().Equals(b.GetHashCode()));
}
}
error: Cannot modify the return value of 'ImmutableKey.Key' because it is not a variable
There are three cases when one can change mutable struct and see result:
local variable: MyStruct s = new MyStruct(); s.Prop = 4;
field of another type: class MyType { public MyStruct S;} ... myType.S.Prop = 4;
element of array: MyStruct[] myArray =...; myArray[3].Prop = 4;.
Why code in the post did not detect change - code used property and not a field.
Note that List<MyStruct> does not allow modification because indexer (this[..]) returns copy of an item (as there is no support returning reference like C++ does).
Related
I have a record definition where I would like to only check equality on public/specific member variables in the record definition. I haven't found a way to do this without making a custom Equals function and I would prefer not to that if there is another nicer solution. Any reflections on whether private member variables in records is a bad pattern or not, is also appreciated.
Example of record where equality is true:
public record Test
{
public string Variable { get; init; }
public Test(string someValue)
{
Variable = someValue;
}
}
[Fact]
public void RecordTest()
{
var test1 = new Test("hello");
var test2 = new Test("hello");
Assert.Equal(test1, test2); // Passes
}
Example of record where I would like it to be true, but it's not:
public record Test
{
// I believe this is causing it to fail, can it be ignored somehow?
private readonly List<string> _list = new();
public string Variable { get; init; }
public Test(string someValue)
{
Variable = someValue;
_list.Add(someValue);
}
}
[Fact]
public void RecordTest()
{
var test1 = new Test("hello");
var test2 = new Test("hello");
Assert.Equal(test1, test2); // Fails
}
In the microsoft documentation you can read this:
For records, value equality means that two variables of a record type
are equal if the types match and all property and field values match.
For other reference types such as classes, equality means reference
equality. That is, two variables of a class type are equal if they
refer to the same object. Methods and operators that determine
equality of two record instances use value equality.
The list here needs to have the same reference for the equality to work.
I think using an equality comparer or override equal is the best way to go.
What about creating your own class that wraps your list, and implement your own object Equals and GetHashCode overrides, as well as implementing IEquatable interface. Then use your own wrapper in the record. Something like:
public class ListWrapper : IEquatable<ListWrapper>
{
private readonly List<string> _list = new();
public void Add(string item) => _list.Add(item);
public bool Equals(ListWrapper other)
{
return _list.SequenceEqual(other._list);
}
// you may or may not want to override object Equals and GetHashCode.
}
public record Test
{
private readonly ListWrapper _list = new();
public string Variable { get; init; }
public Test(string someValue)
{
Variable = someValue;
_list.Add(someValue);
}
}
I am passing a classobject(Cache class object) as a reference in a constructor of Myclass.
public class Test{
static void Main(string[] args){
Cache<string, string> cache;
Myclass obj = new MyClass(ref cache);
obj.doSomething();
Console.WriteLine(cache.key); // I want this value to get changed according to the doSomething Method
Console.WriteLine(cache.value);// I want this value to get changed according to the doSomething Method
}
}
Now in MyClass, I want to set the value of this cache
public class Myclass{
ref Cache<string, string> C;
Myclass(ref Cache<string, string> cache){
this.C = cache;
}
void doSomething(){
C.key = "key";
C.value = "value"
}
}
I want that changing the value of cache in Myclass should reflect in Test Class. But I am not sure how to achieve this. Any help would be appreciated.
Here is the complete scenario which I am trying to do. We have a no of multiple orgs and there are some properties of the org which are same for some org and we don't want to compute those property again and again as it is costly operation. That properties are computed in doSomethingMethod above.
My cache is actually a list. And this cache variable will be passed in the multiple orgs. So in dosomething method I want to check whether the cache is being set or not by any other org and if the key is present I will not compute operation and I will just return from cache.
If you omit the ref keyword, what you give to the constructor is a reference to the cache instance. The reference itself will be a copy, but still reference the same instance. If you then change properties of said instance, it will reflect through all other references to the same instance.
Consider this example:
using System;
public class Program
{
public static void Main()
{
MyCache sharedCache = new MyCache();
Department dpt1 = new Department(sharedCache);
Department dpt2 = new Department(sharedCache);
Console.WriteLine($"Dpt1: {dpt1.CacheValue}");
Console.WriteLine($"Dpt2: {dpt2.CacheValue}");
sharedCache.Value = 1;
Console.WriteLine($"Dpt1: {dpt1.CacheValue}");
Console.WriteLine($"Dpt2: {dpt2.CacheValue}");
dpt1.ChangeValue(2);
Console.WriteLine($"Dpt1: {dpt1.CacheValue}");
Console.WriteLine($"Dpt2: {dpt2.CacheValue}");
}
}
public class Department
{
private readonly MyCache cache;
public Department(MyCache cache)
{
this.cache = cache;
}
public int CacheValue => this.cache.Value;
public void ChangeValue(int newValue)
{
this.cache.Value = newValue;
}
}
public class MyCache
{
public int Value {get; set;} = default;
}
Output:
Dpt1: 0
Dpt2: 0
Dpt1: 1
Dpt2: 1
Dpt1: 2
Dpt2: 2
I've come across an issue that I cannot solve. I've got an IReadOnlyList of classes that each have a bunch of fields. These fields have names (variable names) identical to a list of enums. Think that for each field that exists, an enum for it with the exact same name also exists (so object helloHi has an equivalent enum something { helloHi }).
What I've attempted to do is compare the two field names. If they are identical, perform a function on them. The problem is that the function needs to infer a T from the variable, and since reflection isn't able to pull that 'T' without some form of cast, it won't proceed.
This is the code:
public class Something() {
[BackgroundTask]
private void load(Overlay param_1, Config param_2) {
Children = new Drawable[] // is the IReadOnlyList
{
SomethingClass(param_1),
AnotherClass(param_2)
}
performTask(this, param_2);
}
}
public class Config {
public void task<U>(SomeEnums se, ValueType<U> value) // do the task
}
public class SomethingClass {
ValueType<double> someDouble = new ValueType<double>();
ValueType<int> someInt = new ValueType<int>();
public SomethingClass(Overlay overlay) //...
}
public enum SomeEnums {
someDouble,
someInt,
}
void performTask(Something the_class, Config the_config) {
// ... for each field within the_class, do (uses reflection)
field => {
foreach (SomeEnums enums in Enum.GetValues(typeof(SomeEnums)))
{
if (field.Name == enums.ToString()) {
the_config.task(enums, field.GetValue(null)); // cant infer 'U' from an 'object'
}
}
}
}
Technically, I could just do the config.task within the class where the types are known and visible, but I'd much prefer to automate it from here, so that it doesn't need 2-3 changes every time a new variable is created.
One of the strategies I am aware of is performing an if check within the performTask like such:
// performTask, field =>, foreach
{
if (field.FieldType == ValueType<double>)
config.task(enums, (ValueType<double>)field.GetValue(null));
} //etc
However, I don't like this method. It would just need to introduce more and more checks if I ever created more ValueType<> and if they aren't already being checked for. Would there be a better way to perform what I want?
As I mentioned in my comment, I can't quite tell what you really want to do. However, here's some code that should help you figure it out.
It uses reflection to get the fields of objects, look at the names of those fields (comparing them to the values/names associated with an enum type) and compare the values. I do a comparison to integer 5, but you could compare to anything (but, it appears that the integer type's implementation of IComparable.CompareTo throws if it's compared to something other than an int, so I check). Since you know the type of everything, this is easy to check (you don't have to compare to a fixed Type, you can use what is returned by GetType()).
I started with some auxiliary types:
public enum SomeEnums {
SomeDouble,
SomeInt,
}
public class Class1 {
public int SomeInt = 5;
public double SomeDouble = 3.14;
}
public class Class2 {
public int SomeInt = 5;
public double SomeDouble = 6.28;
}
and then added this:
public class EnumFields {
public List<object> Objects = new List<object> {
new Class1(),
new Class2(),
};
public void PerformTask () {
var enumVals = Enum.GetNames(typeof(SomeEnums));
foreach (var obj in Objects) {
var objType = obj.GetType();
var fieldInfos = objType.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
//right around here I get lost. You have a list of objects (which has two instances right now),
//What are you comparing, that every field named SomeInt has the same value??
//Anyway, here's some code that should help you
foreach (var fieldInfo in fieldInfos) {
if (enumVals.Contains(fieldInfo.Name)) {
var fieldObj = fieldInfo.GetValue(obj);
var isSame = false;
if (fieldObj.GetType() == typeof(int)) {
var comparable = (IComparable)fieldObj;
var same = comparable.CompareTo(5);
isSame = (same == 0);
}
Debug.WriteLine($"Field: {fieldInfo.Name} of instance of {obj.GetType().Name} (Value: {fieldObj}) is equal to 5:{isSame}");
}
}
}
}
}
When I instantiate an EnumFields object and call PerformTask on it, I see this in the output:
Field: SomeInt of instance of Class1 (Value: 5) is equal to 5:True
Field: SomeDouble of instance of Class1 (Value: 3.14) is equal to 5:False
Field: SomeInt of instance of Class2 (Value: 5) is equal to 5:True
Field: SomeDouble of instance of Class2 (Value: 6.28) is equal to 5:False
This should get you most of the way there. I realize it doesn't answer your question. Had I been able to figure out what you were asking, it probably would have.
Consider the flowing code snippet
static void Main()
{
var x = new MyStruct
{
Item = new StringWrapper("abc")
};
Console.WriteLine(x.Item.PublicField);
x.Item.SetValue("xyz");
Console.WriteLine(x.Item.PublicField);
var y = new
{
Item = new StringWrapper("abc")
};
Console.WriteLine(y.Item.PublicField);
y.Item.SetValue("xyz");
Console.WriteLine(y.Item.PublicField);
}
public struct MyStruct
{
public StringWrapper Item;
}
public struct StringWrapper
{
public string PublicField;
public StringWrapper(string v)
{
PublicField = v;
}
public void SetValue(string v)
{
PublicField = v;
}
}
And the output:
abc
xyz
abc
abc
MyStruct can be declared as class, and the output will remain the same.
{abc, abc} part of output is a surprise for me, as I expect anonymous type to be converted to class or struct and behave the same.
I feel like I'm missing something obvious here and will appreciate any help.
Thanks.
The difference here is that your MyStruct (struct or class) exposes a public field while anonymous classes (new { }) expose public properties.
When you access a value type from a field or variable, you do not get a copy, you access the instance directly. Therefore making changes to it stores them in the instance.
When you instead access it via a property or method, you get a returned copy of your StringWrapper and changing that doesn't change what is stored in the anonymous classes private field.
Just to demonstrate, you can get the same behavior by making your Item field a property too:
public StringWrapper Item { get; set; }
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>();
}
}
}