I have these codes:
TAPPUGroup = (APP_UG_USERS, APP_UG_SUPER_USERS, APP_UG_ADMINS);
TAPPUGroups = set of TAPPUGroup;
TAppUser = record
UID: integer;
UName: string;
UGroup: TAPPUGROUPS;
end;
...
LoggedUser: TAppUser;
I used include to add groups to LoggedUser.UGroup, now how I know the index of specific value in TAPPUGroup for example if APP_UG_SUPER_USERS included in LoggedUser.UGroup how I can get it's index in TAPPUGroup ?
Example: If LoggedUser.UGroup = APP_UG_SUPER_USERS then I want to return 1 if LoggedUser.UGroup = APP_UG_ADMINS I want to return 2 and so on.
If you really do want the index of a given enumeration item in the enumeration, all you need to do is just use Ord().
To go the other way, you can use the enumeration name as it it were a function:
AGroup := TAPPUGroup(1);
Anyway, Ord() is how you find the index of a given enumeration value (like APP_UG_USERS) in a contiguous enumeration declaration. To find out whether a particular set instance contains a given set element, ou use the "if xxx in ..." construct Remy shows, e.g.
if APP_UG_USERS in MySet then ...
You can also do this
var
AValue : TAPPUGroup;
MySet : TAPPUGroups ;
for AValue:= Low(TAPPUGroup) to High(TAPPUGroup) do
if AValue in MySet then ...
You don't need the index. To know if a value exists in the Set, use the in operator instead:
if APP_UG_SUPER_USERS in LoggedUser.UGroup then
Related
I have a Map literal, an I want it to be a TreeMap, but by default I believe it's a LinkedHashMap. Casting a LinkedHashMap to a TreeMap won't work as it's not a subtype.
Basically, I'm looking for the simplest way to make this work:
var map = <int, int>{for(int i = 0; i < intervals.length; i++) intervals[i][0] : i} as SplayTreeMap;
As mentioned before, casting as SplayTreeMap won't work as they types don't align.
Thanks much in advance
Use the SplayTreeMap.from constructor to create a SplayTreeMap. There isn't any way to cast it as you said.
Remove the as from your current code and add this to get your SplayTreeMap:
var newMap = SplayTreeMap.from(map);
Depending on your key type and your use case, you can pass compare and isValidKey parameters as well. Full constructor definition:
SplayTreeMap<K, V>.from(
Map other,
[int compare(
K key1,
K key2
),
bool isValidKey(
dynamic potentialKey
)]
)
Is it possible to have a constant set of all items of an enumerated type in Delphi?
type
TItems = (
iOne,
iTwo,
iThree
);
TItemsSet = set of TItems;
const
SOMEITEMS: TItemsSet = [iTwo, iThree];
ALLITEMS: TItemsSet = ?????
I would like ALLITEMS to always hold all members of TItems. And I would prefer to have this as constant.
Edited:
And what, if my enum looks like this:
TItems = (
iOne = 1,
iTwo = 2,
iThree = 5
);
(From the comments)
[Low(T)..High(T)] works for any type T that is small enough to be used as a set, to include all items that can be included in the set.
As noted in the comments, this is enough for the enumeration in the question, but in general, may include constants that aren't defined as part of the enumeration.
I want to create a Pointer to a Class named "CustomParam", so I declared
pCustomParam = ^CustomParam
The Class CustomParam got following class variables, which should be set to 0 in constructor:
var keyArray: array of String;
var valueArray: array of String;
var paramArray: array of pCustomParam;
var isParamArray: array of Boolean;
var size: Integer;
The Constructor looks like that:
constructor CustomParam.create;
begin
inherited;
size:= 0;
SetLength(keyArray,0);
SetLength(valueArray,0);
SetLength(isParamArray,0);
SetLength(paramArray,0);
end;
and was declared like that:
constructor create; overload;
Now I try to create the Pointer to CustomParam with "new" like following:
var pointerToCustomParam: pCustomParam;
begin
new(pointerToCustomParam);
But it don't jump to constructor of CustomParam Class. If I call the constructor manually like following:
pointerToCustomParam^.create;
The application will crash on SetLength commands.
What I noticed is, that the variable "pointerToCustomParam" got rubbish content direct after the "new" function.
I hope you are able to help me and the information are enough :)
Thank you :)
The proper way to create an instance of a type is to call the constructor on the type and assign the result to a variable of that type:
var
Param: CustomParam;
Param := CustomParam.Create;
Instances created that way are already references, so there's rarely a need for an additional pointer.
If you really must have a pointer, then start by declaring the type:
type
PCustomParam = ^CustomParam;
Then declare a variable:
var
Param: PCustomParam;
Allocate memory for the contents of the thing it points to:
New(Param);
That doesn't necessarily assign a valid value to the CustomParam reference it points to, but if it does, is assigns the value nil. So finally, assign a value to that newly allocated memory:
Param^ := CustomParam.Create;
Notice how we still have to call the constructor, and we never call the constructor on the object we're creating, because that object doesn't exist until after the constructor is called.
Your problem is that your declaration
pCustomParam = CustomParam
defines pCustomParam to be of type CustomParam, not a POINTER to Customparam.
Hence pointerToCustomParam will not be a POINTER, but a CustomParam - hence the 'rubbish contents'
Try
pCustomParam = ^CustomParam;
Here's my SQL Server stored procedure :
ALTER PROCEDURE [dbo].[SearchUser]
(#Text NVARCHAR(100),
#TotalRows INT = 0 OUTPUT)
AS
BEGIN
SELECT #TotalRows=1000
SELECT * from Users
END
And my C# code
using (var context = new TestDBEntities())
{
var outputParameter = new ObjectParameter("TotalRows", typeof(Int32));
context.SearchUser("", outputParameter);
Response.Write(outputParameter.Value);
}
However outputParameter.Value always is null.
Could anybody tell me why?
Output parameters filled by its actual values during the execution of the stored procedure.
But table-valued stored procedure actually get executed only in moment when you're trying to iterate resulting recordset, but not calling a wrapper method.
So, this DOES'T work:
using (var context = new TestDBEntities())
{
var outputParameter = new ObjectParameter("TotalRows", typeof(Int32));
context.SearchUser("", outputParameter);
// Paremeter value is null, because the stored procedure haven't been executed
Response.Write(outputParameter.Value);
}
This DOES:
using (var context = new TestDBEntities())
{
var outputParameter = new ObjectParameter("TotalRows", typeof(Int32));
// Procedure does not executes here, we just receive a reference to the output parameter
var results = context.SearchUser("", outputParameter);
// Forcing procedure execution
results.ToList();
// Parameter has it's actual value
Response.Write(outputParameter.Value);
}
When you're working with stored procedures what don't return any recordset, they execute immediately after a method call, so you have actual value in output parameter.
We had a simular issue due to defered excecution our unit tests failed. In short if you have a stored proc that does NOT return anything you need to be sure to set the response type as 'None' when set as 'None' it will be excecuted when called and not defered.
In case you return anything (E.g. Scalar type of String results) it will excecute it when you use the result even if that .Count() or .ToList() is outside of the method that contains the function call.
So try not to force excecution if not need, when needed it should excecute but be sure to declare it correctly or it might not work.
I have same problem before. The main reason I think that the entities framework has the bug in case the user stored procedure has output parameter and return a result set. For example:
ALTER PROCEDURE [dbo].[SearchTest]
(
#RowTotal INT = 0 OUTPUT,
#RowCount INT = 0 OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
SELECT * FROM SomeThing
SELECT #RowTotal = 1233, #RowCount = 5343
END
However if you change the user stored procedure as following, you can get the output params
ALTER PROCEDURE [dbo].[SearchTest]
(
#RowTotal INT = 0 OUTPUT,
#RowCount INT = 0 OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
SELECT #RowTotal = 1233, #RowCount = 5343
END
You can workaround as following:
ALTER PROCEDURE [dbo].[SearchTest]
AS
BEGIN
DECLARE #RowTotal INT, #RowCount INT
SET NOCOUNT ON
SELECT #RowTotal = 1233, #RowCount = 5343
SELECT #RowTotal AS RowTotal, #RowCount AS RowCount, s.*
FROM SomeThing s
END
If anybody has better solution, please tell me
I have a lot of constants that are somehow related, at some point I need to pair them, something like this:
const
key1 = '1';
key2 = '2';
key3 = '3';
value1 = 'a';
value2 = 'b';
value3 = 'c';
I want to avoid doing:
if MyValue = key1 then Result := value1;
I know how to do it with string lists using:
MyStringList.Add(key1 + '=' + value1);
Result := MyStringList.Values[key1];
But, is there any simpler way to do this?
Yes, assignment can be done this way instead, avoiding manual string concatenation:
MyStringList.Values[Key1] := Value1;
Do a wrapper around your "value"
TMyValue = class
value: String;
end;
Then use this:
myValue := TMyValue.Create;
myValue.Value = Value1;
MyStringList.AddObject(Key1, Value1);
Then, you can sort your list, do a IndexOf(Key1) and retrieve the object.
That way, your list is sorted and the search is very fast.
You can use a multi-dimensional constant array with an enumeration for at least one of the dimensions:
Define it like this:
type
TKVEnum = (tKey, tValue); // You could give this a better name
const
Count = 3;
KeyValues: array [1..Count, TKVEnum] of string =
// This is each of your name / value paris
(('1', 'a'), ('2', 'b'), ('3', 'd'));
Then you use it like this:
if MyValue = KeyValues[1, TKVEnum.tKey] then
Result := KeyValues[1, TKVEnum.tValue]
You could use a For loop on it too. This is just as efficient as doing them as individual constant strings, but gives you the added advantage that they are intrinsically associated.
Instead of defining the first dimension numerically, I would suggest
type
TConstPairs = (tcUsername, tcDatabase, tcEtcetera);
But I guess that totally depends on what you constants represent.