I am trying to make some code in my MVC controller (export to Excel) more generic, as I've reached the point where I'm typing out almost identical code in multiple controllers. To make the export to Excel function so that exists in only one place -- rather than in many places -- I had the idea of using a generic IEnumerable so I could feed any IEnumerable into the class. (See code block below.)
I know that I can use byte[] as a parameter (and I might still use that as an other constructor choice), but it would be nice if I could use an IEnumerable in this instance.
However, Intellisense immediately tells me that "the type or namespace T could not be found".
Is is possible to use IEnumerable<T> for this purpose?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication1.CentralFunctions
{
public class ExportToExcel
{
ExportToExcel(IEnumerable<T> inputCollection)
{
// TODO: place my "export to excel" commands here.
}
}
}
You need to define what T represents to the compiler somewhere. Since you are dealing with a class constructor, you need to make the class generic in order to define T.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication1.CentralFunctions
{
public class ExportToExcel<T>
{
ExportToExcel(IEnumerable<T> inputCollection)
{
// TODO: place my "export to excel" commands here.
}
}
}
The T type is «unknown», i.e. not specified.
It seems you want to make the ExportToExcel class generic, and the T seems to be a type parameter:
public class ExportToExcel<T>
{
ExportToExcel(IEnumerable<T> inputCollection)
{
// ...
}
}
You need to declare your T type at class level, If you want you can also add a constraint to T
public class ExportToExcel<T>
{
ExportToExcel(IEnumerable<T> inputCollection)
{
// TODO: place my "export to excel" commands here.
}
}
I have accepted #NightOwl888 as the best answer. Thank you to #Sergei and #Luke for also answering.
Their answers helped me to write the class constructor correctly and now I can greatly simplify my code. I am sharing this because it explains the full context of the question and demonstrates how I can place it into my MVC system. This is the "hello world" version and can serve to help others like me who are figuring out how to get started.
Now I can simplify the controller action to this:
View:
<p>#Html.ActionLink("Export to Excel","ExportToExcel")</p>
Controller Action:
public ActionResult ExportToExcel()
{
IEnumerable<TroveLog> data = db.TroveLogs.AsEnumerable();
var export = new ExportToExcel<TroveLog>(data);
return RedirectToAction("Index");
}
And this is where I can place the single block of code that can export any IEnumerable to Excel. When I use Debug mode (F5), I can see the Debug.WriteLine results and verify that I am seeing the correct information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
namespace WebApplication1.CentralFunctions
{
public class ExportToExcel<T>
{
private IEnumerable<T> data;
public ExportToExcel(IEnumerable<T> inputCollection)
{
this.data = inputCollection;
// Run in Debug Mode (F5) and see results when clicking ActionLink.
Debug.WriteLine("Object: {0}", data.GetType());
Debug.WriteLine("RowCount: {0}", data.Count());
// TODO: place my "export to excel" commands here.
}
}
}
Related
Newby c#/asp.net question here. I am creating a website with .aspx pages.
Within a method I have created a list and added items to it as shown below:
var footballTeams = new List<string>();
footballTeams.Add("Arsenal");
footballTeams.Add("Aston Villa");
footballTeams.Add("Bournemouth");
footballTeams.Add("Brentford");
footballTeams.Add("Brighton & Hove Albion");
footballTeams.Add("Chelsea");
However, I want to move this code into its own separate class - so it is easier to update the teams rather than have to go deep into code.
How would I code this in a class and then be able to call and use the list from another class.
I have tried creating a new folder called App_Code. And then putting a dummy method in it as shown below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace FootballResultPredictor.App_Code
{
public class Class1
{
public static String MyMethod()
{
string myString = "test";
return myString;
}
}
}
However when I try to call the method from the other class, it just can't seem to find it at all as shown here:
Below is the file structure:
I am trying to call a method in Class1.cs from StartNewSeason.aspx
Looking quickly at your code, I have some comments.
-Don't put your new class in a separate folder.
-This code is wrong: string a=myMethod();
because you can't call a method before you have an instance (new...) of a class unless the class is a static class, which is not the case here.
-Coding string b=Class1.MyMethod(), is better, but still wrong, since Class1 is the name of the class not the name of the object.
At this point, I guess the concept of the class and the class object are somewhat not very clear to you.
I suggest that you review this fundamental concept as it is the core of Object Oriented Programming. Also using ASP.NET at this point of your learning path is highly not advisable, I highly recommend that you get to learn OO fundamentals through C# console applications or Windows Forms. These two frameworks, are much simpler to deal with.
When you create a class (of .cs type) file under the same solution in VS it would have a namespace and a class definition. If the class is not static, you refer to it as (other ways can be used as well):
myClassName ObjectName = new myClassName();
The namespace can be specified if the class is in a different project, like new NameSpace2.myClassName, but this is not the case here.
Only after you create an instance (an object) of the non-static class, you can use the object and its method using the ObjectName (not the myClassName). For exmaple:
ObjectName.MethodName();
Back to the program at hand, here is one way to have a separate class handle the list. There are many ways to do this, this way provides validation and allows you to iterate over the list items. Let me know if this is not clear.
The new class is here:
//using System;
//using System.Collections.Generic;
//using System.Data;
public class FootballTeams
{
public List<string> footballTeams = new List<string>();
public FootballTeams()
{
//initialize the list
this.AddFootballTeam("Arsenal");
this.AddFootballTeam("Aston Villa");
this.AddFootballTeam("Bournemouth");
this.AddFootballTeam("Brentford");
this.AddFootballTeam("Brighton & Hove Albion");
this.AddFootballTeam("Chelsea");
}
//Method to add a new team
public void AddFootballTeam(string parmTeam)
{
//validate input
if (string.IsNullOrWhiteSpace(parmTeam))
{ throw new NoNullAllowedException("Error:Team name is empty"); }
if (footballTeams.Contains(parmTeam))
{ throw new DuplicateNameException(); }
//if valid add the name to the list
footballTeams.Add(parmTeam);
}
}
A sample usage of the above class is:
var _t = new FootballTeams();
try
{
_t.AddFootballTeam("Ringers");
}
catch (Exception _ex)
{
Console.WriteLine(_ex.Message);
return;
}
foreach (var _team in _t.footballTeams)
{
Console.WriteLine(_team);
}
The Question In a Nutshell:
How can I get the size of a user defined structure passed as an object to a class library?
Overview:
The point of this test project is to build a class library that wraps up memory sharing using memory mapping within .Net 4 (Or less). In the end I want to be able to define a structure in my main application, pass it to the class library wrapper and let the class library determine the size of the structure.
Definitions:
MyAppA: Main application, the one that will create the memory map
instance initially.
MyAppB: Second application used to communicate
with MyAppA. This will tap into the existing memory map.
MemoryMapTool: This will be the class library that wraps up all the memory sharing.
TestStruct: This will be the structure defined in MyAppA and MyAppB that will be the exact same in both applications but might change from time to time. MemoryMapTool would NOT know the structure layout at any time, it will simply see it as an object.
Initial Idea:
I want the class library wrapper to have no knowledge of the TestStruct generated by MyAppA other than it is an object that the class library wrapper needs to keep up with and use for memory sharing...
I was thinking I would create the TestStruct in MyAppA and add as many variables to it as I needed (in this case just 1, a string). Then pass it into the MemoryMapTool constructor and let the MemoryMapTool class determine the size of the struct. This is currently the issue. Working with memory I tend to be cautious and research before I just try something that will possibly fail killing my IDE or OS... ;)
I was originally going to just pass the TestStruct straight to the MemoryMapTool constructor but ran into this issue...
long lMapSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(oData));
Error: The type or namespace name 'oData' could not be found (are you missing a using directive or an assembly reference?)
I then was thinking of trying to just use...
long lMapSize = System.Runtime.InteropServices.Marshal.SizeOf(oData);
... and it seems to work (at least the IDE likes it). But for some reason I don't feel like that's the correct way to do it.
UPDATE: After trying that I get a new error...
Error: Type 'MyAppA.Form1+TestStruct' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.
Current Source
MemoryMapTool.cs Contents
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.MemoryMappedFiles;
using System.Threading;
namespace SharedMemoryWorker
{
public class MemoryMapTool : IDisposable
{
#region Private class variables
private string m_sLastError = "";
private MemoryMappedFile mmf = null;
private string m_sMapName = "";
private object m_oData = null;
#endregion
#region Public properties
public string MapName
{
get
{
return m_sMapName;
}
set
{
m_sMapName = value;
}
}
public object Data
{
get
{
return m_oData;
}
set
{
m_oData = value;
}
}
#endregion
#region Constructor
private MemoryMapTool(string sMapName, object oData)
{
long lMapSize = System.Runtime.InteropServices.Marshal.SizeOf(oData);
try
{
//Save the map name
m_sMapName = sMapName;
//Create new map or use an existing one
//mmf = MemoryMappedFile.CreateOrOpen(m_sMapName, lMapSize);
}
catch (Exception ex)
{
m_sLastError = ex.Message;
throw new NullReferenceException("Error creating new object!");
}
}
public void Dispose()
{
//Deconstructor
}
#endregion
#region Public class methods
public string GetLastError()
{
return m_sLastError;
}
#endregion
}
}
MyAppA, Form1.cs Contents
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MyAppA
{
public partial class Form1 : Form
{
#region Public structures
public class TestStruct
{
#region Private class variables
private string m_sTest = null;
#endregion
#region Public properties
public string Test
{
get
{
return m_sTest;
}
set
{
m_sTest = value;
}
}
#endregion
}
#endregion
public Form1()
{
InitializeComponent();
}
}
}
MyAppB, Form1.cs Contents
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MyAppB
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}
I think the error is pretty clear. You need to tell the CLR how you want the structure or class members to be laid out in memory. See the StructLayoutAttribute - it needs to be applied explicitly to classes (whereas for structs Sequential is the default).
From your description it appears that you want to do IPC between two or more managed processes. You may also want to establish a unified marshaling strategy for strings (see the MarshalAsAttribute). You can choose one and stick with it throughout your classes.
Finally, I would like to say that this isn't really appropriate for what you're trying to do (too much overhead and room for error). Instead you could:
Still use MMFs but serialize your classes using binary serialization or even JSON.
Design a service oriented architecture based on either WCF or WebAPI (can be selfhosted now, via OWIN/Katana).
Ultimately you can use raw TCP/IP sockets as well and design a small protocol for your apps.
My choice would be #2. Performance can be very good, especially with WCF and on the same computer with named pipes or net.tcp bindings and it just works.
I have created a Area class using Linq-to-SQL.
Now I want to create a partial class of the same name so I can implement validation.
Error 1 Cannot implicitly convert type
'System.Data.Linq.Table<SeguimientoDocente.Area>'
to
'System.Linq.IQueryable<SeguimientoDocente.Models.Area>' C:\Users\Sergio\documents\visual
studio
2010\Projects\SeguimientoDocente\SeguimientoDocente\Models\AreaRepository.cs 14 20 SeguimientoDocente
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SeguimientoDocente.Models
{
public class AreaRepository
{
private SeguimientoDataContext db = new SeguimientoDataContext();
public IQueryable<Area> FindAllAreas()
{
return db.Areas;
}
public Area GetArea(int id)
{
return db.Areas.SingleOrDefault(a => a.ID == id);
}
public void Add(Area area)
{
db.Areas.InsertOnSubmit(area);
}
public void Delete(Area area)
{
db.Areas.DeleteOnSubmit(area);
}
public void Save()
{
db.SubmitChanges();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SeguimientoDocente.Models
{
public partial class Area
{
}
}
Here's a screenshot.
This is almost certainly because your partial class is not in the right namespace. Go into the .designer.cs file of the LINQ model, look for the generated Area class, and make sure the namespace you wrapped your partial class in matches.
EDIT
I just fixed the formatting in your question. The error message does in fact indicate that your partial class is in the wrong namespace.
Error 1 Cannot implicitly convert type
'System.Data.Linq.Table<SeguimientoDocente.Area>'
to
'System.Linq.IQueryable<SeguimientoDocente.Models.Area>'
As you can see from the error above, you need to change the namespace your partial class is in to be SeguimientoDocente, not SeguimientoDocente.Models. As it stands now, they are two completely different incompatible types that happen to have the same simple name.
The error message tells you that the problem is in line 14 of the AreaRepository.cs file. Specifically, you are trying to return db.Areas from a method whose return type is IQueryable<Area>, though db.Areas is in fact of type System.Data.Linq.Table.
Take a look at the following. The question near the end of the code - in the "whoAmI" function...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MY_TEST_PROJECT
{
// a form class
public partial class frmTestForm1 : Form
{
// zillion lines of code
private void aFunction()
{
ClassTest.whoAmI(this);
}
// zillion lines of code
}
// another form class...
public partial class frmTestForm2 : Form
{
// zillion lines of code
private void aFunction()
{
ClassTest.whoAmI(this);
}
// zillion lines of code
}
// a home made test class
public static class ClassTest
{
// zillion lines of code
public static void whoAmI(Form theForm)
{
// IS THERE A WAY TO SEE WHAT KIND OF FORM theForm IS?
// LIKE:
// if (theForm IS A frmTestForm1)
// doThis();
// else if (theForm IS A frmTestForm2)
// doThat();
}
// zillion lines of code
}
}
You can check with the keyword is.
Also, you might want to solve your problem using polymorphism instead of checking the type.
There are few ways you can do this:
as you have guessed you can use "is" key word as Sjoerd has proposed
if (theForm is frmTestForm1)
doThis();
//So on
Another approach is to use reflection to get the exact type of the form you have. Your code should look like somthing like this:
if (theForm.GetType().UnderlyingSystemType
== typeof(frmTestForm1))
doThis();
The drawback of the first approach is that if, for example, your frmTestForm2 is derivative of frmTestForm1 and you use code like this if(yourform is frmTestForm1) and your form is pointing to a frmTestForm2 instance "is" keyword will return true.
Did you try this and it is not working? There is no problem trying to get a type from an object. Although you are sending it in as the base type the object still is a derived class type.
if (theForm.GetType().ToString() == typeof(frmTestForm1).ToString())
{
// Do your stuff
}
(I still feel like a complete newbie in MS Visual environments... so please bear with!)
I'm using Microsoft Visual C# 2008 Express Edition.
I have a project and in that project are two different forms. The .cs file for each form starts out:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace MyNameSpace
{
public partial class MyFormName : Form
{
...
(...and the second is "MyFormName2" but no differences besides that)
I want to write a function that I know both forms are going to need to access. I right-clicked on my project, selected "Add", selected "New Item" then selected "Code File" and named my file "Common.cs" and it gave me a completely blank file that's in my project.
How do I set this up...? I thought I should do the following...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace MyNameSpace
{
}
...but then when I try to add a function like:
public void mytestfunc() {
}
within that namespace I get the following error:
"Expected class, delegate, enum, interface, or struct"
How do I set things up so I can have "mytestfunc" be available to both MyFormName and MyFormName2?
Thanks!
-Adeena
UPDATE:
Understand (now) that everything must be in a class, but then I don't understand how to really use it. Does that mean I have to create an object? This common function happens to just be some math...
so now if I have this:
namespace MyNameSpace
{
public class MyCommonClass
{
public void testFunc()
{
MessageBox.Show("Hee hee!");
return;
}
}
}
...how do I call testFunc from my Form? Must I do the following:
MyCommonClass temp = new MyCommonClass;
temp.testFunc();
or is there another way to call testFunc?
If you do something like:
namespace MyNameSpace
{
public class myclass
{
public myMethod()
{
// Code
}
}
}
You will be able to instantiate and access it. If you change it to:
namespace MyNameSpace
{
public class myclass
{
public static myMethod()
{
// Code
}
}
}
You will be able to call myClass.myMethod without instantiating a new myClass.
The short answer is that everything needs to be inside a class; I'd suggest you sit down with a basic tutorial to help you get to grips with the basics...
Code need to be inside classes.
It would look something like this:
using System;
namespace MyNameSpace
{
public class CommonHelper
{
public string FormatMyData(object obj)
{
//do something
return String.Empty;
}
}
}
If the function you call is not related to the forms, make it static
namespace myns
{
public static class myhelper
{
public static void DoSomething()
{
}
}
}
and call the method using myhelper.DoSomething();
If the function you want to call is somehow form-related, e.g. common functionality across multiple forms, derive a class from Form (does not need a visual form) and make it base class of the visual forms:
namespace myns
{
public class MyFormBase : Form
{
protected void DoSomethingWithTheForm()
{
}
}
}
and in your form's .cs:
namespace myns
{
public partial class MyFormName : MyFormBase
{
}
}