What is the best approach or alternative to constant references?
For the purposes of this question, a 'constant reference' is a reference to an object from which you cannot call methods that modify the object or modify it's properties.
I want something like this:
Const<User> user = provider.GetUser(); // Gets a constant reference to an "User" object
var name = user.GetName(); // Ok. Doesn't modify the object
user.SetName("New value"); // <- Error. Shouldn't be able to modify the object
Ideally, I would mark with a custom attribute (e.g. [Constant]
) every method of a class that doesn't modify the instance, and only those methods can be called from the constant reference. Calls to other methods would result in an error, if possible, during compile time.
The idea is I can return a read-only reference to and be sure that it will not be modified by the client.
c# const-correctness compile-time-constant
add a comment |
For the purposes of this question, a 'constant reference' is a reference to an object from which you cannot call methods that modify the object or modify it's properties.
I want something like this:
Const<User> user = provider.GetUser(); // Gets a constant reference to an "User" object
var name = user.GetName(); // Ok. Doesn't modify the object
user.SetName("New value"); // <- Error. Shouldn't be able to modify the object
Ideally, I would mark with a custom attribute (e.g. [Constant]
) every method of a class that doesn't modify the instance, and only those methods can be called from the constant reference. Calls to other methods would result in an error, if possible, during compile time.
The idea is I can return a read-only reference to and be sure that it will not be modified by the client.
c# const-correctness compile-time-constant
This is called "const
- correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.
– Dai
Nov 25 '18 at 1:20
It is actually an immutable.
– Chris
Nov 25 '18 at 1:23
If you make all properties virtual, you can emit proxies while inheriting from the same object. In this case you can in fact doUser u = prov.GetUser(); // gets proxy
– T.S.
Nov 25 '18 at 1:31
@T.S. overriddenvirtual
properties cannot remove property setters which means you won't get a compiler warning, even if the overridden setter throwsNotSupportedException
.
– Dai
Nov 25 '18 at 2:09
@Dai That is correct. Can't be removed. But OP said: "Calls to other methods would result in an error, if possible, during compile time." So, my suggestion is valid. I like it because it is not "way too complex", to emit proxy from the class it inherits
– T.S.
Nov 25 '18 at 15:44
add a comment |
For the purposes of this question, a 'constant reference' is a reference to an object from which you cannot call methods that modify the object or modify it's properties.
I want something like this:
Const<User> user = provider.GetUser(); // Gets a constant reference to an "User" object
var name = user.GetName(); // Ok. Doesn't modify the object
user.SetName("New value"); // <- Error. Shouldn't be able to modify the object
Ideally, I would mark with a custom attribute (e.g. [Constant]
) every method of a class that doesn't modify the instance, and only those methods can be called from the constant reference. Calls to other methods would result in an error, if possible, during compile time.
The idea is I can return a read-only reference to and be sure that it will not be modified by the client.
c# const-correctness compile-time-constant
For the purposes of this question, a 'constant reference' is a reference to an object from which you cannot call methods that modify the object or modify it's properties.
I want something like this:
Const<User> user = provider.GetUser(); // Gets a constant reference to an "User" object
var name = user.GetName(); // Ok. Doesn't modify the object
user.SetName("New value"); // <- Error. Shouldn't be able to modify the object
Ideally, I would mark with a custom attribute (e.g. [Constant]
) every method of a class that doesn't modify the instance, and only those methods can be called from the constant reference. Calls to other methods would result in an error, if possible, during compile time.
The idea is I can return a read-only reference to and be sure that it will not be modified by the client.
c# const-correctness compile-time-constant
c# const-correctness compile-time-constant
edited Nov 25 '18 at 11:59
Leonardo Raele
asked Nov 25 '18 at 1:17
Leonardo RaeleLeonardo Raele
5901923
5901923
This is called "const
- correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.
– Dai
Nov 25 '18 at 1:20
It is actually an immutable.
– Chris
Nov 25 '18 at 1:23
If you make all properties virtual, you can emit proxies while inheriting from the same object. In this case you can in fact doUser u = prov.GetUser(); // gets proxy
– T.S.
Nov 25 '18 at 1:31
@T.S. overriddenvirtual
properties cannot remove property setters which means you won't get a compiler warning, even if the overridden setter throwsNotSupportedException
.
– Dai
Nov 25 '18 at 2:09
@Dai That is correct. Can't be removed. But OP said: "Calls to other methods would result in an error, if possible, during compile time." So, my suggestion is valid. I like it because it is not "way too complex", to emit proxy from the class it inherits
– T.S.
Nov 25 '18 at 15:44
add a comment |
This is called "const
- correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.
– Dai
Nov 25 '18 at 1:20
It is actually an immutable.
– Chris
Nov 25 '18 at 1:23
If you make all properties virtual, you can emit proxies while inheriting from the same object. In this case you can in fact doUser u = prov.GetUser(); // gets proxy
– T.S.
Nov 25 '18 at 1:31
@T.S. overriddenvirtual
properties cannot remove property setters which means you won't get a compiler warning, even if the overridden setter throwsNotSupportedException
.
– Dai
Nov 25 '18 at 2:09
@Dai That is correct. Can't be removed. But OP said: "Calls to other methods would result in an error, if possible, during compile time." So, my suggestion is valid. I like it because it is not "way too complex", to emit proxy from the class it inherits
– T.S.
Nov 25 '18 at 15:44
This is called "
const
- correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.– Dai
Nov 25 '18 at 1:20
This is called "
const
- correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.– Dai
Nov 25 '18 at 1:20
It is actually an immutable.
– Chris
Nov 25 '18 at 1:23
It is actually an immutable.
– Chris
Nov 25 '18 at 1:23
If you make all properties virtual, you can emit proxies while inheriting from the same object. In this case you can in fact do
User u = prov.GetUser(); // gets proxy
– T.S.
Nov 25 '18 at 1:31
If you make all properties virtual, you can emit proxies while inheriting from the same object. In this case you can in fact do
User u = prov.GetUser(); // gets proxy
– T.S.
Nov 25 '18 at 1:31
@T.S. overridden
virtual
properties cannot remove property setters which means you won't get a compiler warning, even if the overridden setter throws NotSupportedException
.– Dai
Nov 25 '18 at 2:09
@T.S. overridden
virtual
properties cannot remove property setters which means you won't get a compiler warning, even if the overridden setter throws NotSupportedException
.– Dai
Nov 25 '18 at 2:09
@Dai That is correct. Can't be removed. But OP said: "Calls to other methods would result in an error, if possible, during compile time." So, my suggestion is valid. I like it because it is not "way too complex", to emit proxy from the class it inherits
– T.S.
Nov 25 '18 at 15:44
@Dai That is correct. Can't be removed. But OP said: "Calls to other methods would result in an error, if possible, during compile time." So, my suggestion is valid. I like it because it is not "way too complex", to emit proxy from the class it inherits
– T.S.
Nov 25 '18 at 15:44
add a comment |
2 Answers
2
active
oldest
votes
The technique you're referring to is called "const
-correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.
Alternatively, there's a much simpler solution using interfaces: because C# (and I think the CLR too) does not support const-correctness (the closest we have is the readonly
field modifier) the .NET base-class-library designers added "read-only interfaces" to common mutable types to allow a object (wheather mutable or immutable) to expose its functionality via an interface that only exposes immutable operations. Some examples include IReadOnlyList<T>
, IReadOnlyCollection<T>
, IReadOnlyDictionary<T>
- while these are all enumerable types the technique is good for singular objects too.
This design has the advantage of working in any language that supports interfaces but not const-correctness.
- For each type (
class
,struct
, etc) in your project that needs to expose data without risk of being changed - or any immutable operations then create an immutable interface. - Modify your consuming code to use these interfaces instead of the concrete type.
Like so:
Supposing we have a mutable class User
and a consuming service:
public class User
{
public String UserName { get; set; }
public Byte PasswordHash { get; set; }
public Byte PasswordSalt { get; set; }
public Boolean ValidatePassword(String inputPassword)
{
Hash inputHash = Crypto.GetHash( inputPassword, this.PasswordSalt );
return Crypto.CompareHashes( this.PasswordHash, inputHash );
}
public void ResetSalt()
{
this.PasswordSalt = Crypto.GetRandomBytes( 16 );
}
}
public static void DoReadOnlyStuffWithUser( User user )
{
...
}
public static void WriteStuffToUser( User user )
{
...
}
Then make an immutable interface:
public interface IReadOnlyUser
{
// Note that the interfaces' properties lack setters.
String UserName { get; }
IReadOnlyList<Byte> PasswordHash { get; }
IReadOnlyList<Byte> PasswordSalt { get; }
// ValidatePassword does not mutate state so it's exposed
Boolean ValidatePassword(String inputPassword);
// But ResetSalt is not exposed because it mutates instance state
}
Then modify your User
class and consumers:
public class User : IReadOnlyUser
{
// (same as before, except need to expose IReadOnlyList<Byte> versions of array properties:
IReadOnlyList<Byte> IReadOnlyUser.PasswordHash => this.PasswordHash;
IReadOnlyList<Byte> IReadOnlyUser.PasswordSalt => this.PasswordSalt;
}
public static void DoReadOnlyStuffWithUser( IReadOnlyUser user )
{
...
}
// This method still uses `User` instead of `IReadOnlyUser` because it mutates the instance.
public static void WriteStuffToUser( User user )
{
...
}
3
Side note: interfaces alone will not protect from un-friendly caller as they can use reflection/cast/dynamic
to callSetXxxx
methods of the implementing class. If this is the case you need both - interfaces and proxy implementation that hides the actual class.
– Alexei Levenkov
Nov 25 '18 at 2:06
3
@AlexeiLevenkov That's no-different to usingconst_cast
in C++ though. I don't think it's worth developing countermeasures to adversarial library consumers anyway, as this is about eliminating potential bugs, not security.
– Dai
Nov 25 '18 at 2:12
Indeed in case of friendly client interfaces are enough. It is unclear how much protection OP is looking for "be sure that it will not be modified by the client" can be read in many different ways.
– Alexei Levenkov
Nov 25 '18 at 2:48
@Alexei Levenkov My intent with this is as Dai said, more related to preventing potential bugs than security. Sorry for not being entirely clear. Good observation nonetheless.
– Leonardo Raele
Nov 25 '18 at 13:27
add a comment |
So, these are the first two ideas I initially had, but don't quite solve the problem.
Using Dynamic Objects:
The first idea I had was creating a Dynamic Object
that would intercept all member invokations and throw an error if the method being called isn't marked with a [Constant]
custom attribute. This approach is problematic because a) We don't have the support of the compiler to check for errors in the code (i.e. method name typos) when dealing with dynamic objects, which might lead to a lot of runtime errors; and b) I intend to use this a lot, and searching for method names by name every time a method is called might have considerable performance impact.
Using RealProxy:
My second idea was using a RealProxy
to wrap the real object and validate the methods being called, but this only works with objects that inherit from MarshalByRefObject
.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53463876%2fwhat-is-the-best-approach-or-alternative-to-constant-references%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The technique you're referring to is called "const
-correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.
Alternatively, there's a much simpler solution using interfaces: because C# (and I think the CLR too) does not support const-correctness (the closest we have is the readonly
field modifier) the .NET base-class-library designers added "read-only interfaces" to common mutable types to allow a object (wheather mutable or immutable) to expose its functionality via an interface that only exposes immutable operations. Some examples include IReadOnlyList<T>
, IReadOnlyCollection<T>
, IReadOnlyDictionary<T>
- while these are all enumerable types the technique is good for singular objects too.
This design has the advantage of working in any language that supports interfaces but not const-correctness.
- For each type (
class
,struct
, etc) in your project that needs to expose data without risk of being changed - or any immutable operations then create an immutable interface. - Modify your consuming code to use these interfaces instead of the concrete type.
Like so:
Supposing we have a mutable class User
and a consuming service:
public class User
{
public String UserName { get; set; }
public Byte PasswordHash { get; set; }
public Byte PasswordSalt { get; set; }
public Boolean ValidatePassword(String inputPassword)
{
Hash inputHash = Crypto.GetHash( inputPassword, this.PasswordSalt );
return Crypto.CompareHashes( this.PasswordHash, inputHash );
}
public void ResetSalt()
{
this.PasswordSalt = Crypto.GetRandomBytes( 16 );
}
}
public static void DoReadOnlyStuffWithUser( User user )
{
...
}
public static void WriteStuffToUser( User user )
{
...
}
Then make an immutable interface:
public interface IReadOnlyUser
{
// Note that the interfaces' properties lack setters.
String UserName { get; }
IReadOnlyList<Byte> PasswordHash { get; }
IReadOnlyList<Byte> PasswordSalt { get; }
// ValidatePassword does not mutate state so it's exposed
Boolean ValidatePassword(String inputPassword);
// But ResetSalt is not exposed because it mutates instance state
}
Then modify your User
class and consumers:
public class User : IReadOnlyUser
{
// (same as before, except need to expose IReadOnlyList<Byte> versions of array properties:
IReadOnlyList<Byte> IReadOnlyUser.PasswordHash => this.PasswordHash;
IReadOnlyList<Byte> IReadOnlyUser.PasswordSalt => this.PasswordSalt;
}
public static void DoReadOnlyStuffWithUser( IReadOnlyUser user )
{
...
}
// This method still uses `User` instead of `IReadOnlyUser` because it mutates the instance.
public static void WriteStuffToUser( User user )
{
...
}
3
Side note: interfaces alone will not protect from un-friendly caller as they can use reflection/cast/dynamic
to callSetXxxx
methods of the implementing class. If this is the case you need both - interfaces and proxy implementation that hides the actual class.
– Alexei Levenkov
Nov 25 '18 at 2:06
3
@AlexeiLevenkov That's no-different to usingconst_cast
in C++ though. I don't think it's worth developing countermeasures to adversarial library consumers anyway, as this is about eliminating potential bugs, not security.
– Dai
Nov 25 '18 at 2:12
Indeed in case of friendly client interfaces are enough. It is unclear how much protection OP is looking for "be sure that it will not be modified by the client" can be read in many different ways.
– Alexei Levenkov
Nov 25 '18 at 2:48
@Alexei Levenkov My intent with this is as Dai said, more related to preventing potential bugs than security. Sorry for not being entirely clear. Good observation nonetheless.
– Leonardo Raele
Nov 25 '18 at 13:27
add a comment |
The technique you're referring to is called "const
-correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.
Alternatively, there's a much simpler solution using interfaces: because C# (and I think the CLR too) does not support const-correctness (the closest we have is the readonly
field modifier) the .NET base-class-library designers added "read-only interfaces" to common mutable types to allow a object (wheather mutable or immutable) to expose its functionality via an interface that only exposes immutable operations. Some examples include IReadOnlyList<T>
, IReadOnlyCollection<T>
, IReadOnlyDictionary<T>
- while these are all enumerable types the technique is good for singular objects too.
This design has the advantage of working in any language that supports interfaces but not const-correctness.
- For each type (
class
,struct
, etc) in your project that needs to expose data without risk of being changed - or any immutable operations then create an immutable interface. - Modify your consuming code to use these interfaces instead of the concrete type.
Like so:
Supposing we have a mutable class User
and a consuming service:
public class User
{
public String UserName { get; set; }
public Byte PasswordHash { get; set; }
public Byte PasswordSalt { get; set; }
public Boolean ValidatePassword(String inputPassword)
{
Hash inputHash = Crypto.GetHash( inputPassword, this.PasswordSalt );
return Crypto.CompareHashes( this.PasswordHash, inputHash );
}
public void ResetSalt()
{
this.PasswordSalt = Crypto.GetRandomBytes( 16 );
}
}
public static void DoReadOnlyStuffWithUser( User user )
{
...
}
public static void WriteStuffToUser( User user )
{
...
}
Then make an immutable interface:
public interface IReadOnlyUser
{
// Note that the interfaces' properties lack setters.
String UserName { get; }
IReadOnlyList<Byte> PasswordHash { get; }
IReadOnlyList<Byte> PasswordSalt { get; }
// ValidatePassword does not mutate state so it's exposed
Boolean ValidatePassword(String inputPassword);
// But ResetSalt is not exposed because it mutates instance state
}
Then modify your User
class and consumers:
public class User : IReadOnlyUser
{
// (same as before, except need to expose IReadOnlyList<Byte> versions of array properties:
IReadOnlyList<Byte> IReadOnlyUser.PasswordHash => this.PasswordHash;
IReadOnlyList<Byte> IReadOnlyUser.PasswordSalt => this.PasswordSalt;
}
public static void DoReadOnlyStuffWithUser( IReadOnlyUser user )
{
...
}
// This method still uses `User` instead of `IReadOnlyUser` because it mutates the instance.
public static void WriteStuffToUser( User user )
{
...
}
3
Side note: interfaces alone will not protect from un-friendly caller as they can use reflection/cast/dynamic
to callSetXxxx
methods of the implementing class. If this is the case you need both - interfaces and proxy implementation that hides the actual class.
– Alexei Levenkov
Nov 25 '18 at 2:06
3
@AlexeiLevenkov That's no-different to usingconst_cast
in C++ though. I don't think it's worth developing countermeasures to adversarial library consumers anyway, as this is about eliminating potential bugs, not security.
– Dai
Nov 25 '18 at 2:12
Indeed in case of friendly client interfaces are enough. It is unclear how much protection OP is looking for "be sure that it will not be modified by the client" can be read in many different ways.
– Alexei Levenkov
Nov 25 '18 at 2:48
@Alexei Levenkov My intent with this is as Dai said, more related to preventing potential bugs than security. Sorry for not being entirely clear. Good observation nonetheless.
– Leonardo Raele
Nov 25 '18 at 13:27
add a comment |
The technique you're referring to is called "const
-correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.
Alternatively, there's a much simpler solution using interfaces: because C# (and I think the CLR too) does not support const-correctness (the closest we have is the readonly
field modifier) the .NET base-class-library designers added "read-only interfaces" to common mutable types to allow a object (wheather mutable or immutable) to expose its functionality via an interface that only exposes immutable operations. Some examples include IReadOnlyList<T>
, IReadOnlyCollection<T>
, IReadOnlyDictionary<T>
- while these are all enumerable types the technique is good for singular objects too.
This design has the advantage of working in any language that supports interfaces but not const-correctness.
- For each type (
class
,struct
, etc) in your project that needs to expose data without risk of being changed - or any immutable operations then create an immutable interface. - Modify your consuming code to use these interfaces instead of the concrete type.
Like so:
Supposing we have a mutable class User
and a consuming service:
public class User
{
public String UserName { get; set; }
public Byte PasswordHash { get; set; }
public Byte PasswordSalt { get; set; }
public Boolean ValidatePassword(String inputPassword)
{
Hash inputHash = Crypto.GetHash( inputPassword, this.PasswordSalt );
return Crypto.CompareHashes( this.PasswordHash, inputHash );
}
public void ResetSalt()
{
this.PasswordSalt = Crypto.GetRandomBytes( 16 );
}
}
public static void DoReadOnlyStuffWithUser( User user )
{
...
}
public static void WriteStuffToUser( User user )
{
...
}
Then make an immutable interface:
public interface IReadOnlyUser
{
// Note that the interfaces' properties lack setters.
String UserName { get; }
IReadOnlyList<Byte> PasswordHash { get; }
IReadOnlyList<Byte> PasswordSalt { get; }
// ValidatePassword does not mutate state so it's exposed
Boolean ValidatePassword(String inputPassword);
// But ResetSalt is not exposed because it mutates instance state
}
Then modify your User
class and consumers:
public class User : IReadOnlyUser
{
// (same as before, except need to expose IReadOnlyList<Byte> versions of array properties:
IReadOnlyList<Byte> IReadOnlyUser.PasswordHash => this.PasswordHash;
IReadOnlyList<Byte> IReadOnlyUser.PasswordSalt => this.PasswordSalt;
}
public static void DoReadOnlyStuffWithUser( IReadOnlyUser user )
{
...
}
// This method still uses `User` instead of `IReadOnlyUser` because it mutates the instance.
public static void WriteStuffToUser( User user )
{
...
}
The technique you're referring to is called "const
-correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.
Alternatively, there's a much simpler solution using interfaces: because C# (and I think the CLR too) does not support const-correctness (the closest we have is the readonly
field modifier) the .NET base-class-library designers added "read-only interfaces" to common mutable types to allow a object (wheather mutable or immutable) to expose its functionality via an interface that only exposes immutable operations. Some examples include IReadOnlyList<T>
, IReadOnlyCollection<T>
, IReadOnlyDictionary<T>
- while these are all enumerable types the technique is good for singular objects too.
This design has the advantage of working in any language that supports interfaces but not const-correctness.
- For each type (
class
,struct
, etc) in your project that needs to expose data without risk of being changed - or any immutable operations then create an immutable interface. - Modify your consuming code to use these interfaces instead of the concrete type.
Like so:
Supposing we have a mutable class User
and a consuming service:
public class User
{
public String UserName { get; set; }
public Byte PasswordHash { get; set; }
public Byte PasswordSalt { get; set; }
public Boolean ValidatePassword(String inputPassword)
{
Hash inputHash = Crypto.GetHash( inputPassword, this.PasswordSalt );
return Crypto.CompareHashes( this.PasswordHash, inputHash );
}
public void ResetSalt()
{
this.PasswordSalt = Crypto.GetRandomBytes( 16 );
}
}
public static void DoReadOnlyStuffWithUser( User user )
{
...
}
public static void WriteStuffToUser( User user )
{
...
}
Then make an immutable interface:
public interface IReadOnlyUser
{
// Note that the interfaces' properties lack setters.
String UserName { get; }
IReadOnlyList<Byte> PasswordHash { get; }
IReadOnlyList<Byte> PasswordSalt { get; }
// ValidatePassword does not mutate state so it's exposed
Boolean ValidatePassword(String inputPassword);
// But ResetSalt is not exposed because it mutates instance state
}
Then modify your User
class and consumers:
public class User : IReadOnlyUser
{
// (same as before, except need to expose IReadOnlyList<Byte> versions of array properties:
IReadOnlyList<Byte> IReadOnlyUser.PasswordHash => this.PasswordHash;
IReadOnlyList<Byte> IReadOnlyUser.PasswordSalt => this.PasswordSalt;
}
public static void DoReadOnlyStuffWithUser( IReadOnlyUser user )
{
...
}
// This method still uses `User` instead of `IReadOnlyUser` because it mutates the instance.
public static void WriteStuffToUser( User user )
{
...
}
edited Nov 25 '18 at 2:10
answered Nov 25 '18 at 1:29
DaiDai
73.3k13118204
73.3k13118204
3
Side note: interfaces alone will not protect from un-friendly caller as they can use reflection/cast/dynamic
to callSetXxxx
methods of the implementing class. If this is the case you need both - interfaces and proxy implementation that hides the actual class.
– Alexei Levenkov
Nov 25 '18 at 2:06
3
@AlexeiLevenkov That's no-different to usingconst_cast
in C++ though. I don't think it's worth developing countermeasures to adversarial library consumers anyway, as this is about eliminating potential bugs, not security.
– Dai
Nov 25 '18 at 2:12
Indeed in case of friendly client interfaces are enough. It is unclear how much protection OP is looking for "be sure that it will not be modified by the client" can be read in many different ways.
– Alexei Levenkov
Nov 25 '18 at 2:48
@Alexei Levenkov My intent with this is as Dai said, more related to preventing potential bugs than security. Sorry for not being entirely clear. Good observation nonetheless.
– Leonardo Raele
Nov 25 '18 at 13:27
add a comment |
3
Side note: interfaces alone will not protect from un-friendly caller as they can use reflection/cast/dynamic
to callSetXxxx
methods of the implementing class. If this is the case you need both - interfaces and proxy implementation that hides the actual class.
– Alexei Levenkov
Nov 25 '18 at 2:06
3
@AlexeiLevenkov That's no-different to usingconst_cast
in C++ though. I don't think it's worth developing countermeasures to adversarial library consumers anyway, as this is about eliminating potential bugs, not security.
– Dai
Nov 25 '18 at 2:12
Indeed in case of friendly client interfaces are enough. It is unclear how much protection OP is looking for "be sure that it will not be modified by the client" can be read in many different ways.
– Alexei Levenkov
Nov 25 '18 at 2:48
@Alexei Levenkov My intent with this is as Dai said, more related to preventing potential bugs than security. Sorry for not being entirely clear. Good observation nonetheless.
– Leonardo Raele
Nov 25 '18 at 13:27
3
3
Side note: interfaces alone will not protect from un-friendly caller as they can use reflection/cast/
dynamic
to call SetXxxx
methods of the implementing class. If this is the case you need both - interfaces and proxy implementation that hides the actual class.– Alexei Levenkov
Nov 25 '18 at 2:06
Side note: interfaces alone will not protect from un-friendly caller as they can use reflection/cast/
dynamic
to call SetXxxx
methods of the implementing class. If this is the case you need both - interfaces and proxy implementation that hides the actual class.– Alexei Levenkov
Nov 25 '18 at 2:06
3
3
@AlexeiLevenkov That's no-different to using
const_cast
in C++ though. I don't think it's worth developing countermeasures to adversarial library consumers anyway, as this is about eliminating potential bugs, not security.– Dai
Nov 25 '18 at 2:12
@AlexeiLevenkov That's no-different to using
const_cast
in C++ though. I don't think it's worth developing countermeasures to adversarial library consumers anyway, as this is about eliminating potential bugs, not security.– Dai
Nov 25 '18 at 2:12
Indeed in case of friendly client interfaces are enough. It is unclear how much protection OP is looking for "be sure that it will not be modified by the client" can be read in many different ways.
– Alexei Levenkov
Nov 25 '18 at 2:48
Indeed in case of friendly client interfaces are enough. It is unclear how much protection OP is looking for "be sure that it will not be modified by the client" can be read in many different ways.
– Alexei Levenkov
Nov 25 '18 at 2:48
@Alexei Levenkov My intent with this is as Dai said, more related to preventing potential bugs than security. Sorry for not being entirely clear. Good observation nonetheless.
– Leonardo Raele
Nov 25 '18 at 13:27
@Alexei Levenkov My intent with this is as Dai said, more related to preventing potential bugs than security. Sorry for not being entirely clear. Good observation nonetheless.
– Leonardo Raele
Nov 25 '18 at 13:27
add a comment |
So, these are the first two ideas I initially had, but don't quite solve the problem.
Using Dynamic Objects:
The first idea I had was creating a Dynamic Object
that would intercept all member invokations and throw an error if the method being called isn't marked with a [Constant]
custom attribute. This approach is problematic because a) We don't have the support of the compiler to check for errors in the code (i.e. method name typos) when dealing with dynamic objects, which might lead to a lot of runtime errors; and b) I intend to use this a lot, and searching for method names by name every time a method is called might have considerable performance impact.
Using RealProxy:
My second idea was using a RealProxy
to wrap the real object and validate the methods being called, but this only works with objects that inherit from MarshalByRefObject
.
add a comment |
So, these are the first two ideas I initially had, but don't quite solve the problem.
Using Dynamic Objects:
The first idea I had was creating a Dynamic Object
that would intercept all member invokations and throw an error if the method being called isn't marked with a [Constant]
custom attribute. This approach is problematic because a) We don't have the support of the compiler to check for errors in the code (i.e. method name typos) when dealing with dynamic objects, which might lead to a lot of runtime errors; and b) I intend to use this a lot, and searching for method names by name every time a method is called might have considerable performance impact.
Using RealProxy:
My second idea was using a RealProxy
to wrap the real object and validate the methods being called, but this only works with objects that inherit from MarshalByRefObject
.
add a comment |
So, these are the first two ideas I initially had, but don't quite solve the problem.
Using Dynamic Objects:
The first idea I had was creating a Dynamic Object
that would intercept all member invokations and throw an error if the method being called isn't marked with a [Constant]
custom attribute. This approach is problematic because a) We don't have the support of the compiler to check for errors in the code (i.e. method name typos) when dealing with dynamic objects, which might lead to a lot of runtime errors; and b) I intend to use this a lot, and searching for method names by name every time a method is called might have considerable performance impact.
Using RealProxy:
My second idea was using a RealProxy
to wrap the real object and validate the methods being called, but this only works with objects that inherit from MarshalByRefObject
.
So, these are the first two ideas I initially had, but don't quite solve the problem.
Using Dynamic Objects:
The first idea I had was creating a Dynamic Object
that would intercept all member invokations and throw an error if the method being called isn't marked with a [Constant]
custom attribute. This approach is problematic because a) We don't have the support of the compiler to check for errors in the code (i.e. method name typos) when dealing with dynamic objects, which might lead to a lot of runtime errors; and b) I intend to use this a lot, and searching for method names by name every time a method is called might have considerable performance impact.
Using RealProxy:
My second idea was using a RealProxy
to wrap the real object and validate the methods being called, but this only works with objects that inherit from MarshalByRefObject
.
answered Nov 25 '18 at 1:18
Leonardo RaeleLeonardo Raele
5901923
5901923
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53463876%2fwhat-is-the-best-approach-or-alternative-to-constant-references%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
This is called "
const
- correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.– Dai
Nov 25 '18 at 1:20
It is actually an immutable.
– Chris
Nov 25 '18 at 1:23
If you make all properties virtual, you can emit proxies while inheriting from the same object. In this case you can in fact do
User u = prov.GetUser(); // gets proxy
– T.S.
Nov 25 '18 at 1:31
@T.S. overridden
virtual
properties cannot remove property setters which means you won't get a compiler warning, even if the overridden setter throwsNotSupportedException
.– Dai
Nov 25 '18 at 2:09
@Dai That is correct. Can't be removed. But OP said: "Calls to other methods would result in an error, if possible, during compile time." So, my suggestion is valid. I like it because it is not "way too complex", to emit proxy from the class it inherits
– T.S.
Nov 25 '18 at 15:44