Strongly typed Guid as generic struct











up vote
17
down vote

favorite












I already make twice same bug in code like following:



void Foo(Guid appId, Guid accountId, Guid paymentId, Guid whateverId)
{
...
}

Guid appId = ....;
Guid accountId = ...;
Guid paymentId = ...;
Guid whateverId =....;

//BUG - parameters are swapped - but compiler compiles it
Foo(appId, paymentId, accountId, whateverId);


OK, I want to prevent these bugs, so I created strongly typed GUIDs:



[ImmutableObject(true)]
public struct AppId
{
private readonly Guid _value;

public AppId(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public AppId(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


And another one for PaymentId:



[ImmutableObject(true)]
public struct PaymentId
{
private readonly Guid _value;

public PaymentId(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public PaymentId(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


These structs are almost same, there is a lot of duplication of code. Isn't is?



I cannot figure out any elegant way to solve it except using class instead of struct. I would rather use struct, because of null checks, less memory footprint, no garbage collector overhead etc...



Do you have some idea how to use struct without duplicating code?










share|improve this question




















  • 1




    Interesting need. I have a question. Leaving the code duplication aside, when you wanted to create one of those structs, you must initialize them with something. How do you make sure they are initialized with the right thing? As in..var appIdStruct=new AppId(paymentId) should not compile
    – bbeda
    9 hours ago












  • I cannot guarantee it. I cannot check everything. Even then space for bugs will decrease a bit.
    – Tomas Kubes
    9 hours ago










  • From that point of view, I think the space for bugs is the same, you are only moving the source to a different place. Also, you are complicating things which will actually increase that space long term. Are you planning to allocate lots of those? Will they live long in memory?
    – bbeda
    9 hours ago












  • Not much, but null checks are also good reason for structs.
    – Tomas Kubes
    9 hours ago















up vote
17
down vote

favorite












I already make twice same bug in code like following:



void Foo(Guid appId, Guid accountId, Guid paymentId, Guid whateverId)
{
...
}

Guid appId = ....;
Guid accountId = ...;
Guid paymentId = ...;
Guid whateverId =....;

//BUG - parameters are swapped - but compiler compiles it
Foo(appId, paymentId, accountId, whateverId);


OK, I want to prevent these bugs, so I created strongly typed GUIDs:



[ImmutableObject(true)]
public struct AppId
{
private readonly Guid _value;

public AppId(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public AppId(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


And another one for PaymentId:



[ImmutableObject(true)]
public struct PaymentId
{
private readonly Guid _value;

public PaymentId(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public PaymentId(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


These structs are almost same, there is a lot of duplication of code. Isn't is?



I cannot figure out any elegant way to solve it except using class instead of struct. I would rather use struct, because of null checks, less memory footprint, no garbage collector overhead etc...



Do you have some idea how to use struct without duplicating code?










share|improve this question




















  • 1




    Interesting need. I have a question. Leaving the code duplication aside, when you wanted to create one of those structs, you must initialize them with something. How do you make sure they are initialized with the right thing? As in..var appIdStruct=new AppId(paymentId) should not compile
    – bbeda
    9 hours ago












  • I cannot guarantee it. I cannot check everything. Even then space for bugs will decrease a bit.
    – Tomas Kubes
    9 hours ago










  • From that point of view, I think the space for bugs is the same, you are only moving the source to a different place. Also, you are complicating things which will actually increase that space long term. Are you planning to allocate lots of those? Will they live long in memory?
    – bbeda
    9 hours ago












  • Not much, but null checks are also good reason for structs.
    – Tomas Kubes
    9 hours ago













up vote
17
down vote

favorite









up vote
17
down vote

favorite











I already make twice same bug in code like following:



void Foo(Guid appId, Guid accountId, Guid paymentId, Guid whateverId)
{
...
}

Guid appId = ....;
Guid accountId = ...;
Guid paymentId = ...;
Guid whateverId =....;

//BUG - parameters are swapped - but compiler compiles it
Foo(appId, paymentId, accountId, whateverId);


OK, I want to prevent these bugs, so I created strongly typed GUIDs:



[ImmutableObject(true)]
public struct AppId
{
private readonly Guid _value;

public AppId(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public AppId(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


And another one for PaymentId:



[ImmutableObject(true)]
public struct PaymentId
{
private readonly Guid _value;

public PaymentId(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public PaymentId(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


These structs are almost same, there is a lot of duplication of code. Isn't is?



I cannot figure out any elegant way to solve it except using class instead of struct. I would rather use struct, because of null checks, less memory footprint, no garbage collector overhead etc...



Do you have some idea how to use struct without duplicating code?










share|improve this question















I already make twice same bug in code like following:



void Foo(Guid appId, Guid accountId, Guid paymentId, Guid whateverId)
{
...
}

Guid appId = ....;
Guid accountId = ...;
Guid paymentId = ...;
Guid whateverId =....;

//BUG - parameters are swapped - but compiler compiles it
Foo(appId, paymentId, accountId, whateverId);


OK, I want to prevent these bugs, so I created strongly typed GUIDs:



[ImmutableObject(true)]
public struct AppId
{
private readonly Guid _value;

public AppId(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public AppId(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


And another one for PaymentId:



[ImmutableObject(true)]
public struct PaymentId
{
private readonly Guid _value;

public PaymentId(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public PaymentId(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


These structs are almost same, there is a lot of duplication of code. Isn't is?



I cannot figure out any elegant way to solve it except using class instead of struct. I would rather use struct, because of null checks, less memory footprint, no garbage collector overhead etc...



Do you have some idea how to use struct without duplicating code?







c# generics struct guid






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 9 hours ago

























asked 9 hours ago









Tomas Kubes

11.9k1269101




11.9k1269101








  • 1




    Interesting need. I have a question. Leaving the code duplication aside, when you wanted to create one of those structs, you must initialize them with something. How do you make sure they are initialized with the right thing? As in..var appIdStruct=new AppId(paymentId) should not compile
    – bbeda
    9 hours ago












  • I cannot guarantee it. I cannot check everything. Even then space for bugs will decrease a bit.
    – Tomas Kubes
    9 hours ago










  • From that point of view, I think the space for bugs is the same, you are only moving the source to a different place. Also, you are complicating things which will actually increase that space long term. Are you planning to allocate lots of those? Will they live long in memory?
    – bbeda
    9 hours ago












  • Not much, but null checks are also good reason for structs.
    – Tomas Kubes
    9 hours ago














  • 1




    Interesting need. I have a question. Leaving the code duplication aside, when you wanted to create one of those structs, you must initialize them with something. How do you make sure they are initialized with the right thing? As in..var appIdStruct=new AppId(paymentId) should not compile
    – bbeda
    9 hours ago












  • I cannot guarantee it. I cannot check everything. Even then space for bugs will decrease a bit.
    – Tomas Kubes
    9 hours ago










  • From that point of view, I think the space for bugs is the same, you are only moving the source to a different place. Also, you are complicating things which will actually increase that space long term. Are you planning to allocate lots of those? Will they live long in memory?
    – bbeda
    9 hours ago












  • Not much, but null checks are also good reason for structs.
    – Tomas Kubes
    9 hours ago








1




1




Interesting need. I have a question. Leaving the code duplication aside, when you wanted to create one of those structs, you must initialize them with something. How do you make sure they are initialized with the right thing? As in..var appIdStruct=new AppId(paymentId) should not compile
– bbeda
9 hours ago






Interesting need. I have a question. Leaving the code duplication aside, when you wanted to create one of those structs, you must initialize them with something. How do you make sure they are initialized with the right thing? As in..var appIdStruct=new AppId(paymentId) should not compile
– bbeda
9 hours ago














I cannot guarantee it. I cannot check everything. Even then space for bugs will decrease a bit.
– Tomas Kubes
9 hours ago




I cannot guarantee it. I cannot check everything. Even then space for bugs will decrease a bit.
– Tomas Kubes
9 hours ago












From that point of view, I think the space for bugs is the same, you are only moving the source to a different place. Also, you are complicating things which will actually increase that space long term. Are you planning to allocate lots of those? Will they live long in memory?
– bbeda
9 hours ago






From that point of view, I think the space for bugs is the same, you are only moving the source to a different place. Also, you are complicating things which will actually increase that space long term. Are you planning to allocate lots of those? Will they live long in memory?
– bbeda
9 hours ago














Not much, but null checks are also good reason for structs.
– Tomas Kubes
9 hours ago




Not much, but null checks are also good reason for structs.
– Tomas Kubes
9 hours ago












1 Answer
1






active

oldest

votes

















up vote
21
down vote



accepted










First off, this is a really good idea. A brief aside:



I wish C# made it easier to create cheap typed wrappers around integers, strings, ids, and so on. We are very "string happy" and "integer happy" as programmers; lots of things are represented as strings and integers which could have more information tracked in the type system; we don't want to be assigning customer names to customer addresses. A while back I wrote a series of blog posts (never finished!) about writing a virtual machine in OCaml, and one of the best things I did was wrapped every integer in the virtual machine with a type that indicates its purpose. That prevented so many bugs! OCaml makes it very easy to create little wrapper types; C# does not.



Second, I would not worry too much about duplicating the code. It's mostly an easy copy-paste, and you are unlikely to edit the code much or make mistakes. Spend your time solving real problems. A little copy-pasted code is not a big deal.



If you do want to avoid the copy-pasted code, then I would suggest using generics like this:



struct App {}
struct Payment {}

[ImmutableObject(true)]
public struct Id<T>
{
private readonly Guid _value;
public Id(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public Id(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


And now you're done. You have types Id<App> and Id<Payment> instead of AppId and PaymentId, but you still cannot assign an Id<App> to Id<Payment> or Guid.



Also, if you like using AppId and PaymentId then at the top of your file you can say



using AppId = MyNamespace.Whatever.Id<MyNamespace.Whatever.App>


and so on.



Third, you will probably need a few more features in your type; I assume this is not done yet. For example, you'll probably need equality, so that you can check to see if two ids are the same.



Fourth, be aware that default(Id<App>) still gives you an "empty guid" identifier, so your attempt to prevent that does not actually work; it will still be possible to create one. There is not really a good way around that.






share|improve this answer























  • "There is not really a good way around that." Is there a bad way?
    – BurnsBA
    8 hours ago










  • @BurnsBA: You could try to educate your developers not to do that. A static analysis tool (e.g., coding contracts) could probably be configured to detect this sort of error. You could use a class instead of a struct. There are plenty of bad ways. Anyhow, keep in mind that avoiding default is also an issue for normal Guids (in fact, it's an issue for any struct).
    – Brian
    7 hours ago








  • 1




    @BurnsBA: If it hurts when you do that, don't do it! :-)
    – Eric Lippert
    7 hours ago










  • @BurnsBA You can check the state of the structure in every method and throw an exception if the guid is empty. This way, you will probably not be informed immediately when it is created, but eventually yes.
    – IllidanS4
    2 hours ago










  • Do you think it would be useful to have a conversion to Guid defined for the type, or to have a public read-only property exposing the Guid? This would be useful for interfacing persistence frameworks, where the “raw” Guid is required.
    – dasblinkenlight
    28 mins ago











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


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53748675%2fstrongly-typed-guid-as-generic-struct%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
21
down vote



accepted










First off, this is a really good idea. A brief aside:



I wish C# made it easier to create cheap typed wrappers around integers, strings, ids, and so on. We are very "string happy" and "integer happy" as programmers; lots of things are represented as strings and integers which could have more information tracked in the type system; we don't want to be assigning customer names to customer addresses. A while back I wrote a series of blog posts (never finished!) about writing a virtual machine in OCaml, and one of the best things I did was wrapped every integer in the virtual machine with a type that indicates its purpose. That prevented so many bugs! OCaml makes it very easy to create little wrapper types; C# does not.



Second, I would not worry too much about duplicating the code. It's mostly an easy copy-paste, and you are unlikely to edit the code much or make mistakes. Spend your time solving real problems. A little copy-pasted code is not a big deal.



If you do want to avoid the copy-pasted code, then I would suggest using generics like this:



struct App {}
struct Payment {}

[ImmutableObject(true)]
public struct Id<T>
{
private readonly Guid _value;
public Id(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public Id(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


And now you're done. You have types Id<App> and Id<Payment> instead of AppId and PaymentId, but you still cannot assign an Id<App> to Id<Payment> or Guid.



Also, if you like using AppId and PaymentId then at the top of your file you can say



using AppId = MyNamespace.Whatever.Id<MyNamespace.Whatever.App>


and so on.



Third, you will probably need a few more features in your type; I assume this is not done yet. For example, you'll probably need equality, so that you can check to see if two ids are the same.



Fourth, be aware that default(Id<App>) still gives you an "empty guid" identifier, so your attempt to prevent that does not actually work; it will still be possible to create one. There is not really a good way around that.






share|improve this answer























  • "There is not really a good way around that." Is there a bad way?
    – BurnsBA
    8 hours ago










  • @BurnsBA: You could try to educate your developers not to do that. A static analysis tool (e.g., coding contracts) could probably be configured to detect this sort of error. You could use a class instead of a struct. There are plenty of bad ways. Anyhow, keep in mind that avoiding default is also an issue for normal Guids (in fact, it's an issue for any struct).
    – Brian
    7 hours ago








  • 1




    @BurnsBA: If it hurts when you do that, don't do it! :-)
    – Eric Lippert
    7 hours ago










  • @BurnsBA You can check the state of the structure in every method and throw an exception if the guid is empty. This way, you will probably not be informed immediately when it is created, but eventually yes.
    – IllidanS4
    2 hours ago










  • Do you think it would be useful to have a conversion to Guid defined for the type, or to have a public read-only property exposing the Guid? This would be useful for interfacing persistence frameworks, where the “raw” Guid is required.
    – dasblinkenlight
    28 mins ago















up vote
21
down vote



accepted










First off, this is a really good idea. A brief aside:



I wish C# made it easier to create cheap typed wrappers around integers, strings, ids, and so on. We are very "string happy" and "integer happy" as programmers; lots of things are represented as strings and integers which could have more information tracked in the type system; we don't want to be assigning customer names to customer addresses. A while back I wrote a series of blog posts (never finished!) about writing a virtual machine in OCaml, and one of the best things I did was wrapped every integer in the virtual machine with a type that indicates its purpose. That prevented so many bugs! OCaml makes it very easy to create little wrapper types; C# does not.



Second, I would not worry too much about duplicating the code. It's mostly an easy copy-paste, and you are unlikely to edit the code much or make mistakes. Spend your time solving real problems. A little copy-pasted code is not a big deal.



If you do want to avoid the copy-pasted code, then I would suggest using generics like this:



struct App {}
struct Payment {}

[ImmutableObject(true)]
public struct Id<T>
{
private readonly Guid _value;
public Id(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public Id(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


And now you're done. You have types Id<App> and Id<Payment> instead of AppId and PaymentId, but you still cannot assign an Id<App> to Id<Payment> or Guid.



Also, if you like using AppId and PaymentId then at the top of your file you can say



using AppId = MyNamespace.Whatever.Id<MyNamespace.Whatever.App>


and so on.



Third, you will probably need a few more features in your type; I assume this is not done yet. For example, you'll probably need equality, so that you can check to see if two ids are the same.



Fourth, be aware that default(Id<App>) still gives you an "empty guid" identifier, so your attempt to prevent that does not actually work; it will still be possible to create one. There is not really a good way around that.






share|improve this answer























  • "There is not really a good way around that." Is there a bad way?
    – BurnsBA
    8 hours ago










  • @BurnsBA: You could try to educate your developers not to do that. A static analysis tool (e.g., coding contracts) could probably be configured to detect this sort of error. You could use a class instead of a struct. There are plenty of bad ways. Anyhow, keep in mind that avoiding default is also an issue for normal Guids (in fact, it's an issue for any struct).
    – Brian
    7 hours ago








  • 1




    @BurnsBA: If it hurts when you do that, don't do it! :-)
    – Eric Lippert
    7 hours ago










  • @BurnsBA You can check the state of the structure in every method and throw an exception if the guid is empty. This way, you will probably not be informed immediately when it is created, but eventually yes.
    – IllidanS4
    2 hours ago










  • Do you think it would be useful to have a conversion to Guid defined for the type, or to have a public read-only property exposing the Guid? This would be useful for interfacing persistence frameworks, where the “raw” Guid is required.
    – dasblinkenlight
    28 mins ago













up vote
21
down vote



accepted







up vote
21
down vote



accepted






First off, this is a really good idea. A brief aside:



I wish C# made it easier to create cheap typed wrappers around integers, strings, ids, and so on. We are very "string happy" and "integer happy" as programmers; lots of things are represented as strings and integers which could have more information tracked in the type system; we don't want to be assigning customer names to customer addresses. A while back I wrote a series of blog posts (never finished!) about writing a virtual machine in OCaml, and one of the best things I did was wrapped every integer in the virtual machine with a type that indicates its purpose. That prevented so many bugs! OCaml makes it very easy to create little wrapper types; C# does not.



Second, I would not worry too much about duplicating the code. It's mostly an easy copy-paste, and you are unlikely to edit the code much or make mistakes. Spend your time solving real problems. A little copy-pasted code is not a big deal.



If you do want to avoid the copy-pasted code, then I would suggest using generics like this:



struct App {}
struct Payment {}

[ImmutableObject(true)]
public struct Id<T>
{
private readonly Guid _value;
public Id(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public Id(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


And now you're done. You have types Id<App> and Id<Payment> instead of AppId and PaymentId, but you still cannot assign an Id<App> to Id<Payment> or Guid.



Also, if you like using AppId and PaymentId then at the top of your file you can say



using AppId = MyNamespace.Whatever.Id<MyNamespace.Whatever.App>


and so on.



Third, you will probably need a few more features in your type; I assume this is not done yet. For example, you'll probably need equality, so that you can check to see if two ids are the same.



Fourth, be aware that default(Id<App>) still gives you an "empty guid" identifier, so your attempt to prevent that does not actually work; it will still be possible to create one. There is not really a good way around that.






share|improve this answer














First off, this is a really good idea. A brief aside:



I wish C# made it easier to create cheap typed wrappers around integers, strings, ids, and so on. We are very "string happy" and "integer happy" as programmers; lots of things are represented as strings and integers which could have more information tracked in the type system; we don't want to be assigning customer names to customer addresses. A while back I wrote a series of blog posts (never finished!) about writing a virtual machine in OCaml, and one of the best things I did was wrapped every integer in the virtual machine with a type that indicates its purpose. That prevented so many bugs! OCaml makes it very easy to create little wrapper types; C# does not.



Second, I would not worry too much about duplicating the code. It's mostly an easy copy-paste, and you are unlikely to edit the code much or make mistakes. Spend your time solving real problems. A little copy-pasted code is not a big deal.



If you do want to avoid the copy-pasted code, then I would suggest using generics like this:



struct App {}
struct Payment {}

[ImmutableObject(true)]
public struct Id<T>
{
private readonly Guid _value;
public Id(string value)
{
var val = Guid.Parse(value);
CheckValue(val);
_value = val;
}

public Id(Guid value)
{
CheckValue(value);
_value = value;
}

private static void CheckValue(Guid value)
{
if(value == Guid.Empty)
throw new ArgumentException("Guid value cannot be empty", nameof(value));
}

public override string ToString()
{
return _value.ToString();
}
}


And now you're done. You have types Id<App> and Id<Payment> instead of AppId and PaymentId, but you still cannot assign an Id<App> to Id<Payment> or Guid.



Also, if you like using AppId and PaymentId then at the top of your file you can say



using AppId = MyNamespace.Whatever.Id<MyNamespace.Whatever.App>


and so on.



Third, you will probably need a few more features in your type; I assume this is not done yet. For example, you'll probably need equality, so that you can check to see if two ids are the same.



Fourth, be aware that default(Id<App>) still gives you an "empty guid" identifier, so your attempt to prevent that does not actually work; it will still be possible to create one. There is not really a good way around that.







share|improve this answer














share|improve this answer



share|improve this answer








edited 9 hours ago

























answered 9 hours ago









Eric Lippert

532k14510441925




532k14510441925












  • "There is not really a good way around that." Is there a bad way?
    – BurnsBA
    8 hours ago










  • @BurnsBA: You could try to educate your developers not to do that. A static analysis tool (e.g., coding contracts) could probably be configured to detect this sort of error. You could use a class instead of a struct. There are plenty of bad ways. Anyhow, keep in mind that avoiding default is also an issue for normal Guids (in fact, it's an issue for any struct).
    – Brian
    7 hours ago








  • 1




    @BurnsBA: If it hurts when you do that, don't do it! :-)
    – Eric Lippert
    7 hours ago










  • @BurnsBA You can check the state of the structure in every method and throw an exception if the guid is empty. This way, you will probably not be informed immediately when it is created, but eventually yes.
    – IllidanS4
    2 hours ago










  • Do you think it would be useful to have a conversion to Guid defined for the type, or to have a public read-only property exposing the Guid? This would be useful for interfacing persistence frameworks, where the “raw” Guid is required.
    – dasblinkenlight
    28 mins ago


















  • "There is not really a good way around that." Is there a bad way?
    – BurnsBA
    8 hours ago










  • @BurnsBA: You could try to educate your developers not to do that. A static analysis tool (e.g., coding contracts) could probably be configured to detect this sort of error. You could use a class instead of a struct. There are plenty of bad ways. Anyhow, keep in mind that avoiding default is also an issue for normal Guids (in fact, it's an issue for any struct).
    – Brian
    7 hours ago








  • 1




    @BurnsBA: If it hurts when you do that, don't do it! :-)
    – Eric Lippert
    7 hours ago










  • @BurnsBA You can check the state of the structure in every method and throw an exception if the guid is empty. This way, you will probably not be informed immediately when it is created, but eventually yes.
    – IllidanS4
    2 hours ago










  • Do you think it would be useful to have a conversion to Guid defined for the type, or to have a public read-only property exposing the Guid? This would be useful for interfacing persistence frameworks, where the “raw” Guid is required.
    – dasblinkenlight
    28 mins ago
















"There is not really a good way around that." Is there a bad way?
– BurnsBA
8 hours ago




"There is not really a good way around that." Is there a bad way?
– BurnsBA
8 hours ago












@BurnsBA: You could try to educate your developers not to do that. A static analysis tool (e.g., coding contracts) could probably be configured to detect this sort of error. You could use a class instead of a struct. There are plenty of bad ways. Anyhow, keep in mind that avoiding default is also an issue for normal Guids (in fact, it's an issue for any struct).
– Brian
7 hours ago






@BurnsBA: You could try to educate your developers not to do that. A static analysis tool (e.g., coding contracts) could probably be configured to detect this sort of error. You could use a class instead of a struct. There are plenty of bad ways. Anyhow, keep in mind that avoiding default is also an issue for normal Guids (in fact, it's an issue for any struct).
– Brian
7 hours ago






1




1




@BurnsBA: If it hurts when you do that, don't do it! :-)
– Eric Lippert
7 hours ago




@BurnsBA: If it hurts when you do that, don't do it! :-)
– Eric Lippert
7 hours ago












@BurnsBA You can check the state of the structure in every method and throw an exception if the guid is empty. This way, you will probably not be informed immediately when it is created, but eventually yes.
– IllidanS4
2 hours ago




@BurnsBA You can check the state of the structure in every method and throw an exception if the guid is empty. This way, you will probably not be informed immediately when it is created, but eventually yes.
– IllidanS4
2 hours ago












Do you think it would be useful to have a conversion to Guid defined for the type, or to have a public read-only property exposing the Guid? This would be useful for interfacing persistence frameworks, where the “raw” Guid is required.
– dasblinkenlight
28 mins ago




Do you think it would be useful to have a conversion to Guid defined for the type, or to have a public read-only property exposing the Guid? This would be useful for interfacing persistence frameworks, where the “raw” Guid is required.
– dasblinkenlight
28 mins ago


















draft saved

draft discarded




















































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.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • 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.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53748675%2fstrongly-typed-guid-as-generic-struct%23new-answer', 'question_page');
}
);

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







Popular posts from this blog

What visual should I use to simply compare current year value vs last year in Power BI desktop

Alexandru Averescu

Trompette piccolo