I am reading the book Essentials C# 3.0 for .NET framework 3.5 from Mark Michaelis. Since there are more classes involved I was hoping somebody had worked through the book and maybe had the same problem.
The code in chapter 7 fails(page 300). Listing 7.2 shows how to integrate an interface, I've written all of the code like it says in the book.
I'm getting the error:
'xxxx.ConsoleListControl.DisplayHeader(string[])': not all code path returns a value.
The code in question is:
public static void List(string[] headers, Ilistable[] items)
{
int[] columnWidths = DisplayHeaders(headers);
for (int count = 0; count < items.Length; count++)
{
string[] values = items[count].ColumnValues;
DisplayItemsRow(columnWidths, values);
}
}
/// <summary>
/// Displays the column headers
/// </summary>
/// <returns>returns an array of column widths</returns>
private static int[] DisplayHeaders(string[] headers)
{
}
private static void DisplayItemsRow(int[] columnWidths,string[] values)
{
}
}
The string[] headers arefilled with 4 items (FirstName, LastName, Address, Phone).
I don't know what is causing this problem, or how to fix it. I see DisplayHeaders has no value, and columnwidths also has no value.
I haven't put all of the code here; there are 5 classes and 1 interface. I thought maybe that would be to much and not be needed. If somebody wants all the code I will be happy to put it here.
Turn the page, or read again. I guess you're supposed to write code in the method, as it has a return type but no return statement.
Edit: alright, downloaded the PDF, the book explicitly says above this code listing:
Consider another example
And in the code it says:
private static int[] DisplayHeaders(string[] headers)
{
// ...
}
The // ... part indicates something not interesting to the concept being explained is left out for brevity.
The code is shown to explain what an interface can do (in this case printing a list of any kind of object that implements Ilistable), the static helper methods are irrelevant to this. The code is not meant to be run.
Any method that has a type other than void must return an object of that type. So DisplayHeaders must return an integer array.
private static int[] DisplayHeaders(string[] headers)
private - access modifier; indicates this method can only be called from within the class
static - static modifier; this method does not need an instance to be called
int[] - return type; this is the type of the object that this method will return
DisplayHeaders - method name; this is how you refer to this method
(string[] headers) - parameters; this indicates which arguments you need to pass to the method
We can infer from the method summary that its implementation may look something like this:
/// <summary>
/// Displays the column headers
/// </summary>
/// <returns>returns an array of column widths</returns>
private static int[] DisplayHeaders(string[] headers)
{
// builds a new int array with the same
// number of elements as the string array parameter
int[] widths = new int[headers.Length];
for (int i = 0; i < headers.Length; i++)
{
Console.WriteLine(headers[i]); // displays each header in the Console
widths[i] = headers[i].Length; // populates the array with the string sizes
}
// the return keyword instructs the program to send the variable
// that follows back to the code that called this method
return widths;
}
I would continue reading the chapter. More than likely the author fills in the implementation details of that method later on.
The method DisplayHeaders says it returns an array of integers (int[]) but it is not in fact returning anything. There is quite likely code a little bit later on that fills in the method to do something useful, but in order to make the code compile, it needs to return an array. A simple way to do that would be to change it to
private static int[] DisplayHeaders(string[] headers)
{
return new int[0];
}
This causes it to return an empty array of integers.
Related
This question already has answers here:
Changing size of array in extension method does not work?
(3 answers)
Closed 6 years ago.
Using this answer to the question "How to add a string to a string[] array? There's no .Add function" I am trying to use this answer to write an generic extension to append elements to an generic array. Only using the Array.Resize() method works well and the sample below adds an extra element to my string array
string[] array = new string[] { "Foo", "Bar" };
Array.Resize(ref array, array.Length + 1);
array[array.Length - 1] = "Baz";
But when I try to use the ArrayExtension method described below, the method does resize my array inside the method but when it returns the array is unchanged?
My extension class
public static class ArrayExtensions
{
public static void Append<T>(this T[] array, T append)
{
Array.Resize(ref array, array.Length + 1);
array[array.Length - 1] = append; // < Adds an extra element to my array
}
}
Used as follows
string[] array = new string[] { "Foo", "Bar" };
array.Append("Baz");
When the method returns, the added element does not exist. What am I missing?
UPDATE
As pointed out, this question has been asked and answered here before. I will accept the previous question "Changing size of array in extension method does not work?" as an answer to my question.
UPDATE 2
Since if a return method is used in the extension method it does violate the expected behaviour of similar classes in the framework that Append() to modify the object itself, I did some changes to the extension method to prevent it from being falsely used. Thanks #NineBerry for pointing this out.
I also added params T[] add to allow for adding multiple elements at once.
public static class ArrayExtensions
{
/// <summary>
/// Creates a copy of an object array and adds the extra elements to the created copy
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="array"></param>
/// <param name="add">Elemet to add to the created copy</param>
/// <returns></returns>
public static T[] CopyAddElements<T>(this T[] array, params T[] add)
{
for (int i = 0; i < add.Length; i++)
{
Array.Resize(ref array, array.Length + 1);
array[array.Length - 1] = add[i];
}
return array;
}
}
Usage
string[] array = new string[] { "Foo", "Bar" };
array = array.CopyAddElements("Baz", "Foobar");
for (int i = 0; i < array.Length; i++)
{
System.Console.Write($"{array[i]} ");
}
/* Output
* Foo Bar Baz Foobar
*/
Array.Resize creates a new array. That's why you have to pass the array using the ref keyword to Array.Resize. So, after returning from Array.Resize, the variable array references a different object.
There is no way to use an extension method to do what you are trying to do.
Why not simply use a List<> instead of an array? Using Array.Resize is a very costly operation. It means allocating new memory and copying over the data from the old array to the new array each time it is called to increase the array length.
What actually happens is that
array.Append("Baz");
Is translated to
ArrayExtensions.Append( array, "Baz" );
Which means that reference to array is passed in by value, so inside the Append method you work with a copy of the reference. The Array.Resize method then takes this new variable as ref, creates a new array in memory and changes the variable to point to it. Unfortunately, this changes just this variable and not the original one.
You can return the newly created array as return value or create a static method that uses ref instead of extension methods.
Contrary to your intuition the this parameter is not passed with an implicit ref and it is also not allowed to add a ref to it. See also the discussion here
Context
I've been trying out jbEvain's powerful Mono.Cecil library for just about two weeks now. I've created the following function :
/// <summary>
/// Returns true only if they match.
/// </summary>
private bool CompareMethodDefinitionWithCodeFunction(
EnvDTE.CodeFunction pCodeFunction,
Mono.Cecil.MethodDefinition pMethodDefintion)
{
return pMethodDefintion.Name.Equals(pCodeFunction.Name)
&& pMethodDefintion.Parameters.Count == pCodeFunction.Parameters.Count;
}
Goal
The goal is to determine whether pCodeFunction and pMethodDefinition are refering to the same function definition or not. So far, I am able to compare the functions' names and the number of parameters they have. I am well aware that it's not enough to certify that they really are refering to the same function. I need help on improving my comparison. For instance, I believe one should always compare the parameter types in order to take potential function overrides into account.
Previous attempts
I have tried comparing the parameter types but none of my attempts prevailed. Allow me to demonstrate.
I thought I could compare the types as strings so I added abit of code like so :
/// <summary>
/// Returns true only if they match.
/// </summary>
private bool CompareMethodDefinitionWithCodeFunction(
EnvDTE.CodeFunction pCodeFunction,
Mono.Cecil.MethodDefinition pMethodDefintion)
{
foreach (ParameterDefinition paramDef in pMethodDefintion.Parameters)
{
Debug.WriteLine(paramDef.ParameterType.FullName);
}
foreach (CodeElement ce in pCodeFunction.Parameters)
{
CodeParameter codeParameter = ce as CodeParameter;
Debug.WriteLine(codeParameter.Type.AsFullName);
}
return pMethodDefintion.Name.Equals(pCodeFunction.Name)
&& pMethodDefintion.Parameters.Count == pCodeFunction.Parameters.Count;
}
Given that pCodeFunction was refering to the following VB.Net function at runtime
Public Function SomeFunction(ByVal arg As List(Of String)) As Object
Return New Object()
End Function
I got the following output
System.Collections.Generic.List`1<System.String>
System.Collections.Generic.List(Of System.String)
I would prefer not to mess around with these two output values and try to parse them so that they match because this doesn't seem like a very "reliable" way to compare types. What is be the most reliable way to compare the parameter types?
Bonus Notes
This function must be able to seek a function's definition so long as the source code is either VB or C#.
I am currently using the latest Mono.Cecil build (3.12.1) which you can download here
If you want to use my function and insert it in a test class that you've made, you will need the following imports :
using EnvDTE;
using Mono.Cecil;
I believe, after a few more attemps at comparing them appropriately, that there aren't any "proper" ways available out there to compare these two types of objects.
But, I have found a different solution that implies calculating a function index relative to every other function defined within the class. It can get a tiny bit complicated when we start taking the constructors defined in the IL code in consideration but I still think it's appropriate to post this answer out here since it has been my final solution so far. And to be quite frank, the solution as a whole is quite simple.
Allow me to lay out a simple class for demonstrative purposes :
class Class1
{
public static void Function1(string arg1, string arg2)
{
//business logic
}
public static Object Function2(Object arg1)
{
//business logic
}
public static void Function2(List<string> arg1)
{
//business logic
}
}
Function Index
What is my function index supposed to be? Using my Class1 example, simply put, the function's corresponding indexes would be :
0
1
2
Of course, the said function index isn't some property that comes with EnvDTE. I will have to calculate it myself. To implement it, I created a class that contains a EnvDTE.CodeFunction property as well as an int property (intended for the function index).
public class CodeFunctionWithIndex
{
public CodeFunction CodeFunction { get; set; }
public int Index { get; set; }
}
As for our Mono.Cecil.MethodDefinition's function indexes, since we are looping on them (see main post), we can easily calculate their indexes.
It doesn't simply end here though! There are a few things that I need to mention if you want to use the same approach.
To my limited understanding of what goes on behind Mono.Cecil's convenient library, the list of MethodDefinition we are looping through contains all the functions that were generated in IL code after our dll was compiled. But, the class from which our EnvDTE.CodeFunctions reside isn't compiled.
Does a Mono.Cecil.Type (AKA class) contain as many functions as a EnvDTE.ProjectItem (refering to the class)?
No!
Here is what we will have to consider : the constructor(s). A class may or may not have explicitly defined constuctors. But, a Mono.Cecil.Type (AKA the class object of Mono.Cecil) must contain at least one constructor. And believe me, if you don't explicitly define your own constructor, there will be one in the Mono.Cecil.Type!
Finding out if a constructor is explicitly defined within our EnvDTE.ProjectItem(refering to the class) isn't such a hard task. Well... unless you consider the following code complicated.
private List<CodeFunctionWithIndex> GetExplicitlyDefinedConstructors(vsCMElement pRequestedCodeElementKind, CodeElements pCodeElements)
{
int nbCodeFunction = 0; //calculated function index
List<CodeFunctionWithIndex> constructorList = new List<CodeFunctionWithIndex>();
if (pCodeElements != null)
{
foreach (CodeElement element in pCodeElements)
{
//if current element is a namespace
if (element.Kind == vsCMElement.vsCMElementNamespace)
{
constructorList = GetExplicitlyDefinedConstructors(pRequestedCodeElementKind, ((EnvDTE.CodeNamespace)element).Members);
if (!constructorList.Any())
continue;
return constructorList;
}
//if current element is a class
else if (element.Kind == vsCMElement.vsCMElementClass)
{
nbCodeFunction = 0;
constructorList = GetExplicitlyDefinedConstructors(pRequestedCodeElementKind, ((EnvDTE.CodeClass)element).Members);
if (!constructorList.Any()) //because there might be more than one class defined within the active file
continue;
return constructorList;
}
//if current element's kind equals the requested kind
else if (element.Kind == pRequestedCodeElementKind)
{
nbCodeFunction++;
//if it's a constructor, add its index to the list of constructor indexes
if (((CodeFunction)element).FunctionKind.ToString().Contains(vsCMFunction.vsCMFunctionConstructor.ToString()))
{
constructorList.Add(
new CodeFunctionWithIndex()
{
CodeFunction = ((CodeFunction)element),
Index = nbCodeFunction
});
}
}
}
}
return constructorList;
}
And here is how I am calling this function to find out if I have any explicitly defined constructors :
GetExplicitlyDefinedConstructors(
vsCMElement.vsCMElementFunction,
DTE.ActiveDocument.ProjectItem.FileCodeModel.CodeElements)
.Any();
But, if there aren't any constructors defined in it, how can our Mono.Cecil.MethodDefinition's function index match with our EnvDTE.CodeFunction's function index?.
Here is the big idea of my solution (tested) :
In VB.Net, if there is no explicitly defined constructor within the class, the constructor in the IL code will be situated at the beguining of the class (function index 0).
In C#.Net, if there is no explicitly defined constructor within the class, the constructor in the IL code will be situated at the end of the class (last function index).
Here is what my function CompareMethodDefinitionWithCodeFunction proposed in my first post looks like today (yes it's been renamed... I apologize for that):
public MethodDefinition FindMethodDefinition(CodeFunctionWithIndex pCodeFunction, bool pHasAnExplicitlyDefinedCtor)
{
//Get the assembly that should contain the function we seek
//Note : this is done by comparing pCodeFunction's assembly name to every assembly's name (without the extension)
ModuleDefinition assemblyContainingMethod = assemblies
.Where(assem =>
assem.Name.Split(new char[] { '.' }).FirstOrDefault()
.Equals(pCodeFunction.CodeFunction.ProjectItem.ContainingProject.Properties.Item("AssemblyName").Value, StringComparison.CurrentCultureIgnoreCase))
.FirstOrDefault();
//Get the class that should contain the function we seek
//Note : pCodeFunction.Parent.Name is the class name of our pCodeFunction
TypeDefinition classContainingMethod =
assemblyContainingMethod.Types
.Where(cl => cl.Name.Equals(((CodeClass)pCodeFunction.CodeFunction.Parent).Name))
.FirstOrDefault();
//below is what you want to see
bool isCtorAtIndexZero = DTE.ActiveDocument.ProjectItem.Name.EndsWith(".vb");
int functionIndex = 0;
for (int i = 0; i < classContainingMethod.Methods.Count; i++)
{
if (!pHasAnExplicitlyDefinedCtor && isCtorAtIndexZero && i == 0)
continue;
if (functionIndex == pCodeFunction.Index)
return classContainingMethod.Methods[i];
functionIndex++;
}
return null;
}
This code is extracted from a working project.
The assemblies variable is a class property of type List<ModuleDefinition>. By the time this function is called, it will contain the assembly in which the function we seek can be found.
Bear with me as I can only clarify so much. The project is rather big, in my opinion anyways, and it can perform many operations that I need to omit from this post as it is not directly related to the question in the first place.
Hope this helps at least a tiny bit. I apologize for the wall of text.
I have this example code. What I want to do is to make it so that the "Nums" value can only be written to using the "AddNum" method.
namespace ConsoleApplication1
{
public class Person
{
string myName = "N/A";
int myAge = 0;
List<int> _nums = new List<int>();
public List<int> Nums
{
get
{
return _nums;
}
}
public void AddNum(int NumToAdd)
{
_nums.Add(NumToAdd);
}
public string Name { get; set; }
public int Age { get; set; }
}
}
Somehow, I've tried a bunch of things regarding AsReadOnly() and the readonly keyword, but I can't seem to get it to do what I want it to do.
Here is the sample of the code I have to access the property.
Person p1 = new Person();
p1.Nums.Add(25); //access 1
p1.AddNum(37); //access 2
Console.WriteLine("press any key");
Console.ReadLine();
I really want "access 1" to fail, and "access 2" to be the ONLY way that the value can be set. Thanks in advance for the help.
√ DO use ReadOnlyCollection, a subclass of ReadOnlyCollection,
or in rare cases IEnumerable for properties or return values
representing read-only collections.
The quote from this article.
You should have something like this:
List<int> _nums = new List<int>();
public ReadOnlyCollection<int> Nums
{
get
{
return _nums.AsReadOnly();
}
}
In general, collection types make poor properties because even when a collection is wrapped in ReadOnlyCollection, it's inherently unclear what:
IEnumerable<int> nums = myPerson.Nums;
myPerson.AddNum(23);
foreach(int i in nums) // Should the 23 be included!?
...
is supposed to mean. Is the object returned from Nums a snapshot of the numbers that existed when it called, is it a live view?
A cleaner approach is to have a method called something like GetNumsAsArray which returns a new array each time it's called; it may also be helpful in some cases to have a GetNumsAsList variant depending upon what the caller will want to do with the numbers. Some methods only work with arrays, and some only work with lists, so if only one of the above is provided some callers will have to call it and then convert the returned object to the required type.
If performance-sensitive callers will be needing to use this code a lot, it may be helpful to have a more general-purpose method:
int CopyNumsIntoArray(int sourceIndex, int reqCount, ref int[] dest,
int destIndex, CopyCountMode mode);
where CopyCountMode indicates what the code should do the number of items available starting at sourceIndex is greater or less than reqCount; the method should either return the number of items that were available, or throw an exception if it violated the caller's stated expectations. Some callers might start by create and passing in a 10-item array but be prepared to have the method replace it with a bigger array if there are more than ten items to be returned; others might expect that there will be exactly 23 items and be unprepared to handle any other number. Using a parameter to specify the mode will allow one method to service many kinds of callers.
Although many collection authors don't bother including any method that fits the above pattern, such methods can greatly improve efficiency in cases where code wants to work with a significant minority of a collection (e.g. 1,000 items out of a collection of 50,000). In the absence of such methods, code wishing to work with such a range must either ask for a copy of the whole thing (very wasteful) or request thousands of items individually (also wasteful). Allowing the caller to supply the destination array would improve efficiency in the case where the same method makes many queries, especially if the destination array would be large enough to be put on the large object heap.
HOMEWORK QUESTION:
I need to create a simple trivia game that reads from a CSV file. My data for a particular question is structured as follows: "Question;AnswerA;AnswerB;AnswerC;AnswerD;CorrectAnswerLetter".
We're using a series of getters and setters to hold all the relevant data for a single question object, and I'm running into a problem with the array I've created to hold the four answers.
In my constructor, I'm using this code--which I believe instantiates the Answer array in question:
class TriviaQuestionUnit
{
...
const int NUM_ANSWERS = 4;
string[] m_Answers = new String[NUM_ANSWERS];
public string[] Answer
{
get { return m_Answers[]; }
set { m_Answers = value[];
}
...
// Answer array
public string[] GETAnswer(int index)
{
return m_Questions[index].Answer;
}
...
}
I'm accessing the getter and setter from my TriviaQuestionBank method, which includes this code:
...
const int NUM_QUESTIONS = 15;
TriviaQuestionUnit[] m_Questions = new TriviaQuestionUnit[NUM_QUESTIONS];
...
// Answer array
public string[] GETAnswer(int index)
{
return m_Questions[index].Answer;
}
...
I'm using using StreamReader to read a line of input from my file
...
char delim = ';';
String[] inputValues = inputText.Split(delim);
...
parses the input in an array from which I create the question data. For my four answers, index 1 through 4 in the inputValues array, I populate this question's array with four answers.
...
for (int i = 0; i < NUM_ANSWERS; i++)
{
m_Questions[questionCounter].Answer[i] = inputValues[i + 1];
}
...
I'm getting errors of Syntax code, value expected on the getters/setters in my constructor, and if I change the variable to m_Answers[NUM_QUESTIONS] I get an error that I can't implicitly convert string to String[].
Hopefully I've posted enough code for someone to help point me in the right direction. I feel like I'm missing something obvious, but I just cannot make this work.
Your code has some errors that will cause compilation errors, so my first lesson for you is going to be: listen to the compiler. Some of the errors might seem a bit hard to understand sometimes, but I can ensure you that a lot of other people have had the same problems before; googling a compiler error often gives you examples from other people that are similar to your issue.
You say "In my constructor", but the problem is that your code does not have a constructor. You do however initialize fields and properties on your class and surely enough, the compiler will create a default constructor for you, but you have not defined one yourself. I am not saying that your code does not work because you do not have a constructor, but you might be using the wrong terms.
The first problem is in your first code snippet inside TriviaQuestionUnit. Your first two lines are working correctly, you are creating a constant integer with the value 4 that you use to determine how large your array is going to be and then you initialize the array with that given number.
When you do new string[NUM_ANSWERS] this will create an array, with default (empty) values.
The first problem that arises in your code is the getters and setters. The property expects you to return an array of strings which the method signature in fact is telling us:
public string[] Answer
However, looking at the getter and setter, what is it that you return?
m_Answers is a "reference" to your array, hence that whenever you write m_Answers you are referring to that array. So what happens when we add the square brackets?
Adding [] after the variable name of an array indicates that we want to retrieve a value from within the array. This is called the indexer, we supply it with an index of where we want to retrieve the value from within the array (first value starts at index 0). However, you don't supply it with a value? So what is returned?
Listen to the compiler!
Indexer has 1 parameter(s) but is invoked with (0) argument(s)
What does this tell you? It tells you that it doesn't expect the empty [] but it would expect you to supply the indexer with a number, for instance 0 like this: [0]. The problem with doing that here though, is that this would be a miss-match to the method signature.
So what is it that we want?
We simply want to return the array that we created, so just remove [] and return m_Answers directly like this:
public string[] Answer
{
get { return m_Answers; }
set { m_Answers = value; }
}
Note that you were also missing a curly bracket at the end if the set.
When fixing this, there might be more issues in your code, but trust the compiler and try to listen to it!
Bizarrely the stack collection seems to be missing the rather basic shift and unshift methods* and I'm working in 2.0 so I can't just extend them.
Is there any reasonable technique or alternative collection class to get these methods available? I need push and pop as well.
Edit: looks like the collection I want is indeed a deque which is happily not native to C# :(
Can't use third party libraries at this time so I'll be going with the clunky LinkedList (I say clunky because reading and removing are two operations where shift would be one) but I think I'd recommend the PowerCollections approach to anyone who could use it. Or better yet, upgrading to extension methods.
sigh
* Apologies, I didn't realise these were uncommon terms, I thought I just didn't know where to find them in the API. For reference:
shift = remove first element
unshift = insert element at beginning of collection
I would say use a LinkedList<T>. It has methods for adding and removing from the front, as well as adding and removing from the back. I've never heard of shifting and unshifting, but I'm assuming that's what it means.
Never heard of shift/unshift in a stack. The Stack class does provide Pop, Peek, and Push though.
You are using the wrong class if you want a shift/unshift method. A stack is a Last-In First-Out (LIFO) data structure.
If you want shift/unshift without pop and push, use a Queue. If you want both, I recommend using Deque from the PowerCollections library
You can fake extension methods as long as you are using C# 3.0 targeting 2.0.
Can you describe what the shift/unshift operations are?
By definition Stack class represents a way of managing elements in a collection using the Last In First Out (LIFO) technique for adding and removing elements. LIFO simply means that the last element added to a collection will automatically be the first one removed.
The functionality you want from it is something custom, but easily can be achieved in following way
public class MyStack<T>:Stack<T>{
public void Shift(T item){
// load stack into internal ordered list
// clear stack content
// insert into internal list at desired location
// populate stack with content from internal list
}
public void Unshift(T item){
// load stack into internal ordered list
// clear stack content
// insert into internal list at desired location
// populate stack with content from internal list
}
}
and seems this it-s all :)
This is not exactly the best, but it comes close to being a Javascript array with shift/unshift and push/pop. Its does not hide the inner workings, and you can index any item you want. I has the basic functionality though.
public class JSList<T> : List<T>
{
public JSList() : base() {}
/// <summary>
/// this the add item to the start of the list
/// </summary>
/// <param name="v"></param>
public void Shift(T v)
{
this.Insert(0, v);
}
/// <summary>
/// remove item at the start of the list
/// </summary>
/// <returns></returns>
public T Unshift()
{
var toreturn = default(T);
if (this.Count > 0)
{
toreturn = this[0];
this.RemoveAt(0);
}
return toreturn;
}
/// <summary>
/// Adds object to end of the list
/// </summary>
/// <param name="v"></param>
public void Push(T v)
{
this.Add(v);
}
/// <summary>
/// removes an item at the end of the list
/// </summary>
/// <returns></returns>
public T Pop()
{
var toreturn = default(T);
if (this.Count > 0)
{
toreturn = this[this.Count - 1];
this.RemoveAt(this.Count - 1);
}
return toreturn;
}
public T Peek()
{
return this[this.Count - 1];
}
}
Shift ==> Stack.Pop
Unshift ==> Stack.Push
Unshift doesn't return the number of elements in the Stack, you have the Stack.Count property for that.
Also, there's Stack.Peek, to get the first element without removing it.
Stack<T> class