I have a class with predefined constant strings which are used as keys to retrieve the data from the external storage by provided key.
public class StorageKeys
{
public const string SomeKey = "Foo";
public const string AnotherKey = "Foooo";
}
public interface IStorage
{
string GetValue(string key);
}
Which is used like this:
IStorage t = new Storage();
string value = t.GetValue(StorageKeys.SomeKey);
It works but I'm concerned that potentiality it's possible to call GetValue method with just string argument which can cause an error:
string value = t.GetValue("Illegal key");
That's why I've come up with this idea:
public class StorageKeys
{
public static StorageKeys SomeKey = new StorageKeys("Foo");
public static StorageKeys AnotherKey = new StorageKeys("Foooo");
private StorageKeys(string key)
{
_key = key;
}
private readonly string _key;
public static implicit operator string(StorageKeys key) => key._key;
}
public interface IStorage
{
string GetValue(StorageKeys key);
}
After these changes my method can be used only with correct keys but I think it would decrease a performance because of static properties and implicit casting.
So my question is it a good idea?
Am I overconcerned?
How much slower my second approach would be comparing to the first one?
Is there another way to prevent passing wrong arguments?
Am I overconcerned?
Short answer, yes.
What you are trying to do is prevent passing an invalid argument which isn't what you are supposed to do in the first place, you should consider using an enum IF that is possible, that makes it 99.9% typesafe and almost no checks would be required.
In a situation where you need that param to be a string, just perform a validation in GetValue(string key) and either return a null if you wish to handle that later or just throw an Exception.
Related
C# 7.2 introduces the in modifier for parameters which makes perfect sense for structs and in particular for readonly structs.
It is also allowed to use it for a reference type
void Method(in StringBuilder value) { }
As reference types are passed by reference by default, is the in in the example above just a redundant modifier?
value = null is forbidden when you use in, does it mean that it spares also the copy of the reference address by just passing the original reference to the heap location and blocking changes?
in is compiled to IL in exactly the same way as ref, except in argument is marked with IsReadOnly attribute.
That means in behaves exactly as ref, but compiler (not runtime) enforces that you don't assign value to in argument.
So, as you correctly pointed out - in referenece-type argument is passed by reference (which means reference is not copied and points to original location), but compiler prevents you from changing it. I don't really see much use for it for reference types, but it won't hurt to have that, at least for consistency.
Whilst the other two answers are correct that in parameters end up as ref parameters in the resultant IL, care should be taken with the claim that this prevents the value being copied. This only holds true for readonly structs.
To demonstrate this, consider the following piece of code:
using System;
public struct S1
{
public int A;
public void ChangeA(int a) => A = a;
}
public static class Program
{
static void Main()
{
var s1 = new S1 { A = 1 };
S1Foo(in s1);
Console.WriteLine(s1.A);
}
private static void S1Foo(in S1 s) => s.ChangeA(2);
}
Since we are passing s1 by reference, one might reasonably assume that S1Foo, in calling ChangeA would then change the contents of s1. This doesn't happen though. The reason being that the s1 value is copied and a copy is passed by reference, to prevent such modifications of structs via in parameters.
If we decompile the resultant IL, you see that the code ends up as:
public static class Program
{
private static void Main()
{
S1 s = default(S1);
s.A = 1;
S1 s2 = s;
Program.S1Foo(ref s2);
Console.WriteLine(s2.A);
}
private static void S1Foo([IsReadOnly] [In] ref S1 s)
{
S1 s2 = s;
s2.ChangeA(2);
}
}
However, if we write similar code using a readonly struct, then no copying occurs. I say similar as it isn't possible to write the same code as fields and property have to be readonly in a readonly struct (the clue is in the name):
using System;
public readonly struct S2
{
private readonly int _a;
public int A => _a;
public S2(int a) => _a = a;
public void ChangeA(int a) { }
}
public static class Program
{
static void Main()
{
var s2 = new S2(1);
S2Foo(in s2);
Console.WriteLine(s2.A);
}
private static void S2Foo(in S2 s) => s.ChangeA(2);
}
Then no copy occurs in the resultant IL.
So in summary:
in is effectively a readonly ref,
The value (or reference) is passed by reference,
The compiler prevents modifying fields and properties of that reference to help enforce its readonly-ness,
To further enforce the readonly nature of the parameter, then non-readonly structs are copied before a reference to the copy is passed to the method. This doesn't occur for readonly structs.
From what I understand from official documentation, it means that arguments passed to the method will not be changed inside the method itself:
The in keyword specifies that you are passing the parameter by reference and the called method does not modify the value passed to it.
when using the in keyword with value types, it means that instead of passing the argument by value (meaning creating a new copy of the value), it is passed by reference - so it avoids the unnecessary copying.
The only useful thing I can think of for in with reference types would be generic functions with constraints.
public interface IIntContainer
{
int Value { get; }
}
public readonly struct LargeStruct : IIntContainer
{
public readonly int val0;
public readonly int val1;
// ... lots of other fields
public readonly int val20;
public int Value => val0;
}
public class SmallClass : IIntContainer
{
public int val0;
public int Value => val0;
}
public static class Program
{
static void Main()
{
DoSomethingWithValue(new LargeStruct());
DoSomethingWithValue(new SmallClass());
}
public static void DoSomethingWithValue<T>(in T container) where T : IIntContainer
{
int value = container.Value;
// Do something with value...
}
}
I'm pretty sure that I am duplicating a question, but somehow in my example it doesn't work, please see the code:
class Program
{
static void Main(string[] args)
{
Test test1 = new Test("str", "strrr");
}
}
class Test
{
public string testValue, mType;
public Test(string value, string messageType)
{
this.testValue = value;
this.mType = messageType;
}
public Test (string value) : this (value, messageType)
{
//want to manipulate value and messageType here
}
}
messageType in this constructor public Test (string value) : this (value, messageType) says it doesn't exist in the current context. I want to call it in this way because first of all I want my code instantiating the class with two strings, and then I want to provide value only to one parameter constructor but not lose messageType, because I will use it within this constructor public Test (string value). I read about chaining and instantiating constructors but it seems that this thing is opposite to what I read. Sorry not a lot practice yet with programming if this is a simple question, I would like to know how the code should look. What I have read before pointing this question: Call one constructor from another, How call constructor inside other constructor?, http://www.csharp411.com/constructor-chaining/, it doesn't work for me and again sorry if I am duplicating or doing silly things.
I think what you want to do is call Test test1 = new Test("Value", "MessageType"); to instantiate an object. Then the constructor with two strings will set these parameters to testValue and mType fields and call the first constructor to make manipulations.
In your code the first constructor does not call the second one, actually the second constructor calls the first one. If you want the first constructor to call the second your constructor signatures should be like this:
public Test(string value, string messageType) : this(value)
public Test(string value)
But here you cannot send messageType parameter to the second constructor. Therefore you should write an initialization method, put the content of the second constructor in this method and call it from both constructors and do not use constructor chaining.
public Test(string value, string messageType)
{
this.testValue = value;
this.mType = messageType;
Initialize();
}
public Test(string value)
{
this.testValue = value;
Initialize()
}
public void Initialize()
{
//This is the code in the second constructor
}
So in your example, you have to constructors: one accepting value and type and the other accepting only value. In such case, if the user provides a value only, the type should have a default assumed value. For example, you could do something like:
public Test (string value) : this (value, "Default Message Type")
{
}
What this code does is that it gets the value from the user, i.e. the caller of the constructor, and pass it to the other constructor, along with a default message called "Default Message Type".
Notice that you don't need to put any code in this constructor, since it will call the other constructor which will set both the value and the type.
Hope this helps.
EDIT: From the comments, I understood from that #ArnosGo wants to do some manipulation on value and add some logic that finds the value of messageType, then pass both to the other constructor. Unfortunately, it is not possible to do some manipulation on data before calling the other constructor, but here is a trick to do this:
class Test
{
public string testValue, mType;
public Test(string value, string messageType)
{
Initialise(value, messageType);
}
public Test (string value)
{
// Do some manipulation here and found out the value of messageType.
Initialise(value, messageType);
}
protected void Initialise(string value, string messageType)
{
this.testValue = value;
this.mType = messageType;
}
}
Basically, you are creating a function that does what both constructors do, then the constructors only calculate the values and pass them to that function.
The call to the database and message string comes before creating an
object of Test class and then i want to put two values in it, and then
manipulate those values inside and provide them to constructor with
one parameter. If that explains something.
Based on OP's comment, I think approach with static method will be better
Because values are manipulated only once and properties assigned only once.
public class Test
{
private static ManipulateValues(string value, string msgtype)
{
//Do your manipulating
Return manipulatedValue;
}
public static Create(string value, string msgtype)
{
return new Test(Test.ManipulateValues(value, msgtype), msgtype);
}
public Test(string value, string msgType)
{
this.testValue = value;
this.mType = messageType;
}
}
Then use it:
string messageType = someValue;
string value = someDatabaseValue;
Test temp = Test.Create(value, messageType)
I have an object that represents the current event that is taking place. This event contains a lot of settings. What is the best practice for storing all setting variables inside the event object?
The settings are stored in a database (right now in different columns based on the base class: ValueString, ValueInt, ValueBool, ValueDateTime, ValueFloat, ValueDecimal). A unique key represents the setting in the database.
As soon as i have loaded the events object i will store it in the local cache for quick access.
Should i cast everything to object? (Feels like un-needed casts to get/set settings)
class Event
{
// string = settings key
Dictionary<string, object> _settings;
public void AddSetting(string key, object value)
public object GetSetting(string key)
}
or should i have it in different dictionaries?
class Event
{
// string = settings key
Dictionary<string, string> _settingStrings;
Dictionary<string, int> _settingInts;
...
public void AddSetting(string key, string value)
public void AddSetting(string key, int value)
...
public string GetStringSetting(string key)
public int GetIntSetting(string key)
...
}
Any ideas?
You can store everything as an Object, but rather than performing a straight cast, use generics to build an easy to use API:
private IDictionary<string,object> _settings = new Dictionary<string,object>();
public void AddSetting<T>(string key, T value) {
_settings[key] = value;
}
public T GetSetting<T>(string key, T notFound = default(T)) {
object res;
if (!_settings.TryGetValue(key, out res) || !(res is T)) {
return notFound;
}
return (T)res;
}
The cast remains there, but the API hides it from the user: now the user can safely write
string searchPath = settingContainer.GetSetting<string>("searchPath");
int retryCount = settingContainer.GetSetting<int>("retryCount", -1);
I really do like dasblinkenlight's answer.
Except instead of wasting one column for each datatype, I would rather have only one column (likely a VARCHAR) on your datatable.
Advantages of this:
Faster reading (Only one indexed column)
Saving up storage (Only one varchar per row)
And then you can either use generics as mentioned, or cast the string object in your implementation to your wished type.
I have a function with this signature:
public void DoSomething(String name);
The string name is special in my application. It can be either an arbitrary string, or a special known value. Because any non-empty string value is a valid input it means I need to use object reference equality with empty strings, like so:
public class Foo {
public const String SpecialValue1 = "";
public const String SpecialValue2 = "";
public void DoSomething(String name) {
if( Object.ReferenceEquals( name, SpecialValue1 ) ) {
} else if( Object.ReferenceEquals( name, SpecialValue2 ) {
} else {
}
}
public void UsageExample() {
DoSomething( SpecialValue1 );
DoSomething( "some arbitrary value" );
}
}
I want to know if this technique, using empty strings and object reference equality will always be safe, especially with respect to string interning.
Antimony is right about the reasons this will not work.
I would suggest that you define a type for the argument. Let's call it ExampleArgument.
public class ExampleArgument
{
private readonly int _knownValue;
private readonly string _arbitraryValue;
public ExampleArgument(string arbitraryValue)
{
_arbitraryValue = arbitraryValue;
_knownValue = 0;
}
private ExampleArgument(int knownValue)
{
_knownValue = knownValue;
_arbitraryValue = null;
}
public static readonly ExampleArgument FirstKnownValue = new ExampleArgument(1);
public static readonly ExampleArgument SecondKnownValue = new ExampleArgument(2);
// obvious Equals and GetHashCode overloads
// possibly other useful methods that depend on the application
}
Oh, and if you really want the calling syntax in your example, you could add:
public static implicit operator ExampleArgument(string arbitraryValue)
{
return new ExampleArgument(arbitraryValue);
}
Which is an implicit conversion operator from string to ExampleArgument.
DoSomething(ExampleArgument.FirstKnownValue);
DoSomething(new ExampleArgument("hello"));
DoSomething("hello"); // equivalent to previous line, uses implicit conversion operator
No, this is not safe. In fact, this will never work. String literals get interned, so both special values will have the same reference. Most compilers will also intern compile time constant strings, and you can always intern strings manually.
Unfortunately, if you want to accept any valid string, you need some other way to pass extra information. And even if a hack like this worked, it would be a bad idea, since it violates normal string equality semantics.
Here are the possibilities I can think of
If you only have one special value, you can use null
Take a broader type such as Object as input
Take two parameters
Make a separate function
I have a project I am working that will involve creating one DLL that will be used across multiple other sites. Inside this DLL we need to reference about 10 Enums. The values of these Enums however will be different for each site the DLL is used on. For example:
MyBase.dll may have a class MyClass with an attribute of type MyEnum.
MyBase.dll is then referenced in MySite. MyStie will also reference MyEnums.dll which will contain the values for the MyEnum type.
Is there any way to accomplish this? While building MyBase.dll, I know what enums will exist in side of MyEnums.dll. The problem is I cannot build MyBase.dll without specifically referenceing the MyEnums.dll, which is not created until the MyBase.dll is used in a specific project.
I hope that makes sense and hope I can find an answer here.
Thanks.
Edit:
Thanks for all the comments. It will take a few reads to completely understand, but let me try to give a better example of what I am looking at here.
Lets say the following code is in my DLL that will be put into various projects. Status is an enum.
public Class MyClass
{
private Status _currentStatus;
public Status CurrentStatus
{
get
{
return _currentStatus;
}
}
public void ChangeStatus(Status newStatus)
{
_currentStatus = newStatus;
}
}
What I want to be able to do is the define the possible values for Status in the individual projects. So in this DLL, I will never reference what values might be in the Status enum, I just have to know that it exists.
I hope that is a bit more clear on what I am trying to do.
If you want each client to see different enum values (in a different assembly version), then using an enum is a bad solution - changes will break client code...
Using an enum might work (as long as the enum names and assembly name are the same and the assembly isn't signed) - you could just swap the assembly. However, if a value is used anywhere in the code that isn't there at the end you'll end up with an exception. Also, you may have the explicitly number the values, to make sure different subsets of the values won't end up with the same number for different values or different numbers for the same value.
Instead consider using a dynamically built collection, e.g. a list, a dictionary or a database table. Or just give the same assembly with the same superset of enum values to everyone and let the users decide which values are relevant to them (perhaps use significant prefixes for values as a convention).
Or you could use a combination of the two...
Generate a different structure (different type name (or namespace) and assembly name) per site with different properties (according to site's profile) and one master structure for the service that accepts the structures. Have all the structures implement the same interface, which you expect to receive...
public interface IStatus
{
string GetKey();
}
public struct ClientXStatus : IStatus
{
private readonly string _key;
private ClientXStatus(string key)
{
_key = key;
}
// Don't forget default for structs is 0,
// therefore all structs should have a "0" property.
public ClientXStatus Default
{
get
{
return new ClientXStatus();
}
}
public ClientXStatus OptionB
{
get
{
return new ClientXStatus(10);
}
}
string IStatus.GetKey()
{
return _key;
}
public override bool Equals(object obj)
{
return (obj is IStatus) && ((IStatus)obj).GetKey() == _key;
}
public override int GetHashCode()
{
return _key.GetHashCode();
}
public static bool operator==(ClientXStatus x, IStatus y)
{
return x.Equals(y);
}
public static bool operator==(IStatus x, ClientXStatus y)
{
return y.Equals(x);
}
public static bool operator!=(ClientXStatus x, IStatus y)
{
return !x.Equals(y);
}
public static bool operator!=(IStatus x, ClientXStatus y)
{
return !y.Equals(x);
}
// Override Equals(), GetHashCode() and operators ==, !=
// So clients can compare structures to each other (to interface)
}
Use a master struct for the service:
public struct MasterStatus : IStatus
{
private readonly string _key;
private MasterStatus(string key)
{
_key = key;
}
// Don't forget default for structs is 0,
// therefore all structs should have a "0" property.
public MasterStatus Default
{
get
{
return new MasterStatus();
}
}
// You should have all the options here
public MasterStatus OptionB
{
get
{
return new MasterStatus(10);
}
}
// Here use implicit interface implementation instead of explicit implementation
public string GetKey()
{
return _key;
}
public static implicit operator MasterStatus(IStatus value)
{
return new MasterStatus(value.GetKey());
}
public static implicit operator string(MasterStatus value)
{
return new value._key;
}
// Don't forget to implement Equals, GetHashCode,
// == and != like in the client structures
}
Demo service code:
public void ServiceMethod(IStatus status)
{
switch (status.GetKey())
{
case (string)MasterStructA.OptionB:
DoSomething();
}
}
Or:
public void ChangeStatus(IStatus status)
{
_status = (MasterStatus)status;
}
This way you:
Use code generation to prevent collision of values.
Force users to use compile time checks (no int values or string values) by hiding values (as private) and only accepting your structures.
Use real polymorphism in the service's code (an interface) and not a error-prone hack.
Use immutable value types (like enums) and not reference types.
First you have to decide WHERE to put your constants. Then you can transform your enum to static properties.
For example:
public enum MyEnum
{
Value1,
Value2
}
Can be changed to (first naive approach):
public static class MyFakeEnum
{
public static int Value1
{
get { return GetActualValue("Value1"); }
}
public static int Value2
{
get { return GetActualValue("Value2"); }
}
private static int GetActualValue(string name)
{
// Put here the code to read the actual value
// from your favorite source. It can be a database, a configuration
// file, the registry or whatever else. Consider to cache the result.
}
}
This simply will provide required constants but you'll have to throw away compile-time check for the type if you'll need MyFakeEnum as parameter. For a better solution you can follow, for example, what Microsoft did (more or less) for System.Drawing.Color.
public sealed class MyFakeEnum
{
public static readonly MyFakeEnum Value1 = new MyFakeEnum("Value1");
public static readonly MyFakeEnum Value2 = new MyFakeEnum("Value2");
private MyFakeEnum(string name)
{
_name = name;
}
public static implicit operator int(MyFakeEnum value)
{
return GetActualValue(value._name);
}
private string _name;
}
Of course you should provide proper overides at least for Equals, GetHashCode and ToString.
Pro
It can be an upgrade from an existing enum. Code won't be breaked and you may just need to recompile.
You can use it as strongly typed parameter. For example: void DoSomething(MyFakeEnum value) is valid and callers can't pass something else (note that this is one of the reasons because enums are considered weak).
If you implement all the required operators you can use the normal syntax for comparison: value == MyFakeEnum::Value1.
With a little bit of code you may even implement the FlagsAttribute syntax.
You do not change the normal syntax of enums: MyFakeEnum.Value1.
You can implement any number of implicit/explicit conversion operators to/from your type and any conversion will be safe and checked in the point it's done (this is not true again with standard enums).
You do not have hard-coded strings that can be breaked by changes and won't be catched until they cause a run-time error (yes, run-time). Using, for example, a dictionary if you'll change the definitions then you'll have to search all your code for that string.
Cons
First implementation is longer because you have to write support code (but for any new value you'll simply add a new line).
Value list is fixed and must be known at compile time (this is not an issue if you're searching a replacement for an enum because it's fixed too).
With this solution you may save more or less the same syntax you had with standard enums.