I'm fairly new to C# but i'm looking to convert an object to an array of unsigned shorts. The original data is an array of WORD's (numerical value WORD) passed as an object. I've attempted the following but keep getting an error.
object temp = Agent.Port("PumpPressure1_01").Value;
ushort[] PP1_01 = ((IEnumerable)temp).Cast<object>()
.Select(x => x == null ? x.ToUshort())
.ToArray();
When I run this I get the following error:
'System.Collections.Generic.IEnumerable<T>' requires '1' type arguments.
The namespaces I used when I get the above error are:
using System.Linq;
using System.Text; // Don't think this is required but added it in case
If I add the following namespaces:
using System.Collections;
using System.Collections.Generic;
I get the following error.
'System.Linq.ParalleIEnumerable.Select<TTSource,TResult>()' is not supported by the language
I'm sure this is an obvious issue but I've been hunting the net for a while and can't find a solution. My best guess is that the Select function isn't correct as this was originally designed to convert an object to an array of strings.
Any help would be great.
Thanks
IEnumerable is a generic interface, so you have to declare the datatype you are using...
To be honest though, I would want to check what that call to
object temp = Agent.Port("PumpPressure1_01").Value;
is actually returning - by inspecting it in the debugger... If it is simply returning a reference to an array of a numeric type, you should be able to simply cast it. What you are doing though is trying to cast each individual item within the array - I suspect that's not what you should be doing - which would be casting the array itself.
Can you give us any API documentation for the Port method on the Agent object so I can see what it is meant to return? Can you try the inspection and see what that gives you?
Why you casting to IEnumerable and then casting it back to object if your temp variable is already of type object?
Also IEnumerable<T> is a generic interface and must specify exact type (as exception also says to you). If you have an array of integers and you want to work with them it should be IEnumerable<int>
Thanks for all the help and feedback.
Unfortunately I was't paying enough attention to the warnings that was posted which seems to be causing the issue.
Warning: Reference to type 'System.Func '2' claims it is defined in 'c:\Windows\Microsoft.NET\Framework64\v2.0.50727mscorlib.dll'. but it could not be found
It seems that there is some issue with the .NET reference. I have another VM which I tested the following solution on and it seemed to work without issue. Looks like I'll have to reinstall the software package to get it to work on the VM i want to use.
The software package I'm using is a custom package that uses C# to build solutions with prebuilt classes made to look like plug and play blocks. You can connect the blocks together drawings lines from one input/output of a block to another. You can then build C# code inside the blocks. Basically c# for dummy's like me..
Example of the blocks:
As for the code, I did have to make some changes as follows but now works a treat. Agent.Port("PumpPressure1_01").Value.RawValue is used to reference the particular ports on the block.
object temp = (object)Agent.Port("PumpPressure1_01").Value.RawValue;
UInt16[] PP1_01 = ((System.Collections.IEnumerable)temp).Cast<object>()
.Select(x => Convert.ToUInt16(x))
.ToArray();
foreach(UInt16 x in PP1_01)
{
Agent.LogDebug("values: " + x.ToString());
}
Again, thanks for all the help. Just need to resolve the issue with the library reference now.
Related
I have a huge code base and I recently made a change where I changed the type of a parameter from String to a custom class. On the next compile I got all the areas where the impact was, but areas where the input type was of type Object failed. for e.g.
String str = "32"
int i = Convert.ToInt32(str)
Now I have changed String to a new custom type lets say MyCustomClass I would now want following code to fail on next compile
MyCustomClass str = new MyCustomClass("32")
int i = Convert.ToInt32(str)
but it won't as Convert.ToInt32 also accepts type Object. Is there some way I can make a change in MyCustomClass that it's not considered Object anymore.
Please note: Convert.ToInt32 is only used for sample I have many more such functions, so please focus your suggestion/answer to question asked.
Override ToString() and IConvertible
You said in the comments that your intentions are to find places where your object, which had previously been treated as a string, and are now being treated as an object.
In these situations typically, the third-party code would call .ToString() on your object to get something which it can use.
So, Convert.ToInt32(str) is equivalent to Convert.ToInt32(str.ToString()).
If you implement ToString() and IConvertible to return whatever your old version of str looked like then it should continue to work in the same way as the old version.
Probably.
Sorry I know that is not the 100% perfect compile time answer you were looking for, but I think you also know very well that your MyCustomClass will always be considered object.
Possible compile time answer:
Write a tool which uses reflection to iterate over every class/struct/interface in every system/third-party DLL.
Output a load of CS files which contain all these same classes, but just throw NotImplementedException.
(T4 could help you do this)
Compile these classes into dummy.dll
Your .csproj now references only this one dummy.dll, instead of the real dlls.
Your project should compile fine against the dummy dll.
Look at your dummy.cs files and delete any use of object.
Re-compile... and suddenly you get a load of compile time errors showing you anywhere you are using an object.
Impliment an implicit cast from MyCustomClass to String.
public static implicit operator string(MyCustomClass str)
{
return "Legacy respresentation of str";
}
This allows the complier the choice of choosing ToInt32(Object) or ToInt32(String), and I bet it favours the later.
This way all your existing function calls will remain the same so you wont have to be concerned about third party implentation details.
(Sorry, I am not at a computer right now so I can`t test that my assumtion is correct. If you do test this, be sure to consider extension methods, as they can affect the conpilers desision making in unexpected ways)
Am moving from Excel VBA to VSTO using C#. In VBA I had a 3 line custom function called IsInCollection as shown below:
On Error Resume Next
Set obj = collectionObject(itemObject)
IsInCollection = Not (obj is Nothing)
I used it all the time to check if a given workbook was open, or if a workbook contained a sheet with a particular name, etc. Because the collection and the item arguments are defined as objects it would work with anything.
I'm trying to create the same utility function/method in managed code and am struggling mightily. The problem is with the collectionObject(itemObject) expression. C# doesn't allow me to just index an object as VBA did.
If anybody can point me in the right direction it would be much appreciated. From my searching I've been looking into QueryInterface but am not sure if that's where I should be looking. It seems that an Excel object comes across as a System._ComObject, so presumably I need to iterate through that somehow(?).
TIA
i think you want to check out LINQ. for example you can query collections like
IsInCollection = obj.Any(s => s != null);
The indexing operator in C# is [], not () as in VB. I'm not very familiar with COM though, so if the object you have is just an object/System._ComObject you might have to cast it to the appropriate type first, unless _ComObject has an indexer already.
It seems that finding out what type a _ComObject really is can be be a bit difficult, so you might wanna try a trick I found at http://www.mztools.com/articles/2006/mz2006013.aspx:
var typeName = Microsoft.VisualBasic.Information.TypeName( collectionObject );
I also suspect you could use the System.ComponentModel.TypeDescriptor class.
I have an object DirectoryToken that inherits from the class Token. In my code I have a GetValues method which takes a list of tokens, and puts together the value for each item in the list based on the information contained in the token object.
//NameTokens is an object of type **List<DirectoryToken>**
List<String> PathValues = GetValues((IEnumerable<Token>)settings.DirectoryDefinition.**NameTokens**.OrderBy(x => x.Index));
private List<String> GetReportValues(IEnumerable<Token> TokenList)
{
}
What I notice is when I run the code on one machine (Windows 7, .NET 3.5), it runs fine. However, when I move the built msi to another machine and try to run the same test, I get the following error message.
Unable to cast object of type 'System.Linq.OrderedEnumerable2[DirectoryToken,System.Int32]' to type 'System.Collections.Generic.IEnumerable1[Token]'.
I don't think changing the code is the right way to attack this issue. Any suggestions what this problem could be from and maybe what version I can update my 3.5 to, to remedy this?
You're trying to convert a collection of DirectoryToken to a collection of Token.
This is called a covariant conversion, and it's only supported in .Net 4.0 or later.
If you can't upgrade, you can call .Cast<Token>() to create a new IEnumerable<T> instance (actually an iterator) that casts each object to the desired type.
Under no circumstances do you need an explicit cast operation.
Right, not quite there yet.
List<String> PathValues = GetValues(settings.DirectoryDefinition.NameTokens.OrderBy(x => x.Index).Cast<Token>());
will work.
This is because although DirectoryToken is a Token, IEnumerable<DirectoryToken> is NOT an IEnumerable<Token>. You can't just cast directly do that.
In VB.net, I can write:
If {"red", "blue"}.Contains("blue") Then Return True
and the Contains seems to be from Linq.Enumerable(Of T).
I'm having trouble converting it to C# - when I use an online conversion tool like the one from Developer Fusion, it gives me:
if ({"red", "blue"}.Contains("blue")) return true;
but it doesn't compile, saying it's unable to resolve the symbol Contains which isn't very helpful. I'm sure it's a simple syntax issue, but I'm not sure what you call an example like this.
I don't need to instantiate the array, since I'm just using it to evaluate the expression inline. This seems to be possible in VB.NET. What do you call this - a static array? constant array? anonymous array? some combination of those listed?
I'd like to know how to write this in C#, and also what this is called (I'll update the question title and tags to better reflect what I'm asking when someone can answer that). Thanks!
This would be your direct conversion
if (new []{"red", "blue"}.Contains("blue")) return true;
Oh, it's called an array initializer
I am attempting to process results from a select (Find.., All, etc) from simple.data, but I am getting errors:
var db = Database.Open();
var codes = db.Code.All();
// 'object' does not contain a definition for 'First'
var firstcode = codes.First();
// 'object' does not contain a definition for 'ToList'
List<Code> codeList = codes.ToList();
The type of codes is {System.Linq.Enumerable.WhereSelectListIterator<System.Collections.Generic.IDictionary<string,object>,Simple.Data.DynamicRecord>}.
What am I missing? Someone add a simple.data tag please.. :)
The main reason that LINQ methods don't work on the object returned from db.Code.All() is that at that point in the code, the C# compiler doesn't know that it's an IEnumerable, so it can't hook up the extension methods. Of course, the C# compiler doesn't know what the object is, because it's dynamic, so it passes over it and assumes that the First() method will be resolved at runtime.
I've tried to address this in more recent releases, and many methods are supported, including ToList, First, FirstOrDefault, Single, SingleOrDefault and some others. Still more are to come soon (within the 0.9.x releases).
The easiest way to bring the compiler back into full effect is to explicitly specify the type instead of using var. For example
IEnumerable<Code> codes = db.Codes.All();
will cause an "implicit cast" (quoted because it's not really, but it acts like one) from the SimpleQuery type to the IEnumerable type, at which point you can start using LINQ methods on it again.
Doh, simple answer. I was using the latest version from https://github.com/markrendle/Simple.Data/downloads but in fact it should installed from nuget http://nuget.org/List/Packages/Simple.Data.Core.. :(
It looks like you need a using System.Linq; declaration.
If the actual error message contains the word 'object' then it indicates that the type of codes returned from your call is an object, not a System.Linq.Enumerable.WhereSelectListIterator<System.Collections.Generic.IDictionary<string,object>,Simple.Data.DynamicRecord>} as you say, which would be the cause of the error.