C# Custom Data Converter for Reading Bytes[] - c#

Here is my custom dataconverter helper class which helps me to read the value from DataReader and return
public class DataConvertor<T> where T : IhasIndexer
{
public DataConvertorField<string, T> String;
public DataConvertorField<int, T> Int;
T reader;
public void Initialise(T reader)
{
this.reader = reader;
String = new DataConvertorField<string, T>(reader, Convert.ToString);
Int = new DataConvertorField<int, T>(reader, Convert.ToInt32);
}
public bool has(string name)
{
try
{
object o = reader[name];
return true;
}
catch
{
return false;
}
}
}
public class DataConvertorField<T, O> where O : IhasIndexer
{
O parent;
DataConvertorMethod convertor;
public DataConvertorField(O parent, DataConvertorMethod convertor)
{
this.parent = parent;
this.convertor = convertor;
}
public T this[string name]
{
get
{
if (parent[name] == DBNull.Value)
{
if (typeof(T).Equals(typeof(string)))
return (T)(object)string.Empty;
else
return default(T);
}
else
return convertor(parent[name]);
}
}
public delegate T DataConvertorMethod(object o);
}
public interface IhasIndexer
{
object this[string key] { get; }
}
Then i simply use in my ADO.Net code as below
using (DBDataReaderWrapper reader = cmd.ExecuteReader())
{
while (reader.Read())
{
user.UserId = reader.Int["UserId"];
user.UserName = reader.String["UserName"];
}
public class DBDataReaderWrapper : DataConvertor<DBDataReaderWrapper>,
IDisposable, IhasIndexer
{
SqlDataReader reader;
public DBDataReaderWrapper(SqlDataReader reader)
{
Initialise(this);
this.reader = reader;
}
public object this[string name]
{
get
{
return reader[name];
}
}
public bool Read()
{
return reader.Read();
}
public bool NextResult()
{
return reader.NextResult();
}
public void Dispose()
{
reader.Close();
reader.Dispose();
}
}
}
The question is how can i use my helper class for reading image from Database. I want to add DataConverter like
public DataConvertorField<byte[], T> Bytes;
and in Initialise() method
Bytes = new DataConvertorField<byte[]>(reader, Convert.to??????);
How can i achieve this? any c# built in or helper method available for my need?
So i can use like in ADO.Net code
reader.Bytes["UserImage"]; //use custom data covertor and gives bytes[]

Related

Create new T, X and populate class using reflections C# [duplicate]

While mapping class i am getting error 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method.
Below is my SqlReaderBase Class
public abstract class SqlReaderBase<T> : ConnectionProvider
{
#region Abstract Methods
protected abstract string commandText { get; }
protected abstract CommandType commandType { get; }
protected abstract Collection<IDataParameter> GetParameters(IDbCommand command);
**protected abstract MapperBase<T> GetMapper();**
#endregion
#region Non Abstract Methods
/// <summary>
/// Method to Execute Select Queries for Retrieveing List of Result
/// </summary>
/// <returns></returns>
public Collection<T> ExecuteReader()
{
//Collection of Type on which Template is applied
Collection<T> collection = new Collection<T>();
// initializing connection
using (IDbConnection connection = GetConnection())
{
try
{
// creates command for sql operations
IDbCommand command = connection.CreateCommand();
// assign connection to command
command.Connection = connection;
// assign query
command.CommandText = commandText;
//state what type of query is used, text, table or Sp
command.CommandType = commandType;
// retrieves parameter from IDataParameter Collection and assigns it to command object
foreach (IDataParameter param in GetParameters(command))
command.Parameters.Add(param);
// Establishes connection with database server
connection.Open();
// Since it is designed for executing Select statements that will return a list of results
// so we will call command's execute reader method that return a Forward Only reader with
// list of results inside.
using (IDataReader reader = command.ExecuteReader())
{
try
{
// Call to Mapper Class of the template to map the data to its
// respective fields
MapperBase<T> mapper = GetMapper();
collection = mapper.MapAll(reader);
}
catch (Exception ex) // catch exception
{
throw ex; // log errr
}
finally
{
reader.Close();
reader.Dispose();
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
connection.Close();
connection.Dispose();
}
}
return collection;
}
#endregion
}
What I am trying to do is , I am executine some command and filling my class dynamically. The class is given below:
namespace FooZo.Core
{
public class Restaurant
{
#region Private Member Variables
private int _restaurantId = 0;
private string _email = string.Empty;
private string _website = string.Empty;
private string _name = string.Empty;
private string _address = string.Empty;
private string _phone = string.Empty;
private bool _hasMenu = false;
private string _menuImagePath = string.Empty;
private int _cuisine = 0;
private bool _hasBar = false;
private bool _hasHomeDelivery = false;
private bool _hasDineIn = false;
private int _type = 0;
private string _restaurantImagePath = string.Empty;
private string _serviceAvailableTill = string.Empty;
private string _serviceAvailableFrom = string.Empty;
public string Name
{
get { return _name; }
set { _name = value; }
}
public string Address
{
get { return _address; }
set { _address = value; }
}
public int RestaurantId
{
get { return _restaurantId; }
set { _restaurantId = value; }
}
public string Website
{
get { return _website; }
set { _website = value; }
}
public string Email
{
get { return _email; }
set { _email = value; }
}
public string Phone
{
get { return _phone; }
set { _phone = value; }
}
public bool HasMenu
{
get { return _hasMenu; }
set { _hasMenu = value; }
}
public string MenuImagePath
{
get { return _menuImagePath; }
set { _menuImagePath = value; }
}
public string RestaurantImagePath
{
get { return _restaurantImagePath; }
set { _restaurantImagePath = value; }
}
public int Type
{
get { return _type; }
set { _type = value; }
}
public int Cuisine
{
get { return _cuisine; }
set { _cuisine = value; }
}
public bool HasBar
{
get { return _hasBar; }
set { _hasBar = value; }
}
public bool HasHomeDelivery
{
get { return _hasHomeDelivery; }
set { _hasHomeDelivery = value; }
}
public bool HasDineIn
{
get { return _hasDineIn; }
set { _hasDineIn = value; }
}
public string ServiceAvailableFrom
{
get { return _serviceAvailableFrom; }
set { _serviceAvailableFrom = value; }
}
public string ServiceAvailableTill
{
get { return _serviceAvailableTill; }
set { _serviceAvailableTill = value; }
}
#endregion
public Restaurant() { }
}
}
For filling my class properties dynamically i have another class called MapperBase Class with following methods:
public abstract class MapperBase<T> where T : new()
{
protected T Map(IDataRecord record)
{
T instance = new T();
string fieldName;
PropertyInfo[] properties = typeof(T).GetProperties();
for (int i = 0; i < record.FieldCount; i++)
{
fieldName = record.GetName(i);
foreach (PropertyInfo property in properties)
{
if (property.Name == fieldName)
{
property.SetValue(instance, record[i], null);
}
}
}
return instance;
}
public Collection<T> MapAll(IDataReader reader)
{
Collection<T> collection = new Collection<T>();
while (reader.Read())
{
collection.Add(Map(reader));
}
return collection;
}
}
There is another class which inherits the SqlreaderBaseClass called DefaultSearch. Code is below
public class DefaultSearch: SqlReaderBase<Restaurant>
{
protected override string commandText
{
get { return "Select Name from vw_Restaurants"; }
}
protected override CommandType commandType
{
get { return CommandType.Text; }
}
protected override Collection<IDataParameter> GetParameters(IDbCommand command)
{
Collection<IDataParameter> parameters = new Collection<IDataParameter>();
parameters.Clear();
return parameters;
}
protected override MapperBase<Restaurant> GetMapper()
{
MapperBase<Restaurant> mapper = new RMapper();
return mapper;
}
}
But whenever I tried to build , I am getting error 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method. Even T here is Restaurant has a Parameterless Public constructor.
The problem is that you're trying to use the T from SqlReaderBase as the type argument for MapperBase - but you don't have any constraints on that T.
Try changing your SqlReaderBase declaration to this:
public abstract class SqlReaderBase<T> : ConnectionProvider
where T : new()
Here's a shorter example which demonstrates the same issue:
class Foo<T>
{
Bar<T> bar;
}
class Bar<T> where T : new()
{
}
The fix is to change Foo<T>'s declaration to:
class Foo<T> where T : new()
Then the compiler will know that the T from Foo is a valid type argument for Bar.
The constraints must apply to every type in the chain; hence you need:
public abstract class SqlReaderBase<T> : ConnectionProvider where T : new()
Without this, you can't satisfy the constraint for T in:
protected abstract MapperBase<T> GetMapper();
or
MapperBase<T> mapper = GetMapper();
since MapperBase<> is only usable when T has : new()
I had the same issue. I should have read the message before Googling it. I needed to add a parameterless constructor ... :-)
public MyClass() {
//stuff
}

Deserialize XML String into Class

I am trying to deserialize an XML String into my class which is derived from another class but I am having a problem in doing so, I am getting the following error:
{"The specified type is abstract: name='DeviceRequest', namespace='', at <DeviceRequest xmlns=''>."}
I assume i am missing some decorator attribute that will inform the serializer how to deserialize this xml into the class?
Here is my code:
//Usage
DeviceRequest dreq = DeviceRequest.ParseRequest(e.XML);
//Base Class
public abstract class IFSFRequestBase
{
private string m_ApplicationSender = "";
private int m_WorkStationID = 0;
private string m_RequestID = "";
[XmlAttribute()]
public abstract string RequestType { get; set; }
public abstract byte[] Message();
[XmlAttribute()]
public string ApplicationSender
{
get
{
return m_ApplicationSender;
}
set
{
m_ApplicationSender = value;
}
}
[XmlAttribute()]
public int WorkStationID
{
get
{
return m_WorkStationID;
}
set
{
m_WorkStationID = value;
}
}
[XmlAttribute()]
public string RequestID
{
get
{
return m_RequestID;
}
set
{
m_RequestID = value;
}
}
}
//Derived Class
public abstract class DeviceRequest : IFSFRequestBase
{
private string m_TerminalID = "";
private string m_SequenceID = "";
private Output m_OutputField = null;
[XmlAttribute(), DefaultValue("")]
public string TerminalID
{
get
{
return m_TerminalID;
}
set
{
m_TerminalID = value;
}
}
[XmlAttribute(), DefaultValue("")]
public string SequenceID
{
get
{
return m_SequenceID;
}
set
{
m_SequenceID = value;
}
}
[XmlElement("Output")]
public Output OutputField
{
get
{
return m_OutputField;
}
set
{
m_OutputField = value;
}
}
public static DeviceRequest ParseRequest(string sXML)
{
XmlSerializer serializer = new XmlSerializer(typeof(DeviceRequest));
StringReader sr = new StringReader(sXML);
NamespaceIgnorantXmlTextReader XMLWithoutNamespace = new NamespaceIgnorantXmlTextReader(sr);
return (DeviceRequest)serializer.Deserialize(XMLWithoutNamespace);
}
}
// helper class to ignore namespaces when de-serializing
public class NamespaceIgnorantXmlTextReader : XmlTextReader
{
public NamespaceIgnorantXmlTextReader(System.IO.TextReader reader) : base(reader) { }
public override string NamespaceURI
{
get { return ""; }
}
}
UPDATE:
OK based on the answers here. I have updated the code, I now have a class Display that derives from DeviceRequest. I now get the following error:
{"There is an error in XML document (2, 2)."}, {"<DeviceRequest xmlns=''> was not expected."}
public class Display : DeviceRequest
{
public static Display ParseRequest(string sXML)
{
XmlSerializer serializer = new XmlSerializer(typeof(Display));
StringReader sr = new StringReader(sXML);
NamespaceIgnorantXmlTextReader XMLWithoutNamespace = new NamespaceIgnorantXmlTextReader(sr);
return (Display)serializer.Deserialize(XMLWithoutNamespace);
}
[XmlAttribute()]
public override string RequestType
{
get { return "Output"; } set { }
}
public override byte[] Message()
{
throw new NotImplementedException();
}
}
DeviceRequest dreq = Display.ParseRequest(e.XML);
As DeviceRequest is an abstract type, it cannot be instantiated directly. It is impossible to directly deserialize into instances of Device-Request. That said, if there are some non-abstract classes derived from it, please show some of them.
OK, I have resolved this issue now. Thanks for the input guys.
I needed to add:
[System.Xml.Serialization.XmlRootAttribute(ElementName = "DeviceRequest")]
to the Display Class
[System.Xml.Serialization.XmlRootAttribute(ElementName = "DeviceRequest")]
public class Display : DeviceRequest
{
public static Display ParseRequest(string sXML)
{
XmlSerializer serializer = new XmlSerializer(typeof(Display));
StringReader sr = new StringReader(sXML);
NamespaceIgnorantXmlTextReader XMLWithoutNamespace = new NamespaceIgnorantXmlTextReader(sr);
return (Display)serializer.Deserialize(XMLWithoutNamespace);
}
[XmlAttribute()]
public override string RequestType
{
get { return "O"; } set { }
}
public override byte[] Message()
{
throw new NotImplementedException();
}
}

There was an error generating the XML document at Serialize method

as this link , I have public property although this error There was an error generating the XML document occur at ser.Serialize(sw, this); in SaveToXML method.
I have this class as parent, it has one property too!
public class XMLCollection<T> where T: new ()
{
private XmlSerializer ser;
private List<T> m_InnerList= new List<T>();
public List<T> InnerList {
get
{ return m_InnerList; }
set
{ m_InnerList = value; }
}
public XMLCollection()
{
ser = new XmlSerializer(this.GetType(), new XmlRootAttribute(this.GetType().Name ));
}
/// <summary>
///
/// </summary>
/// <param name="path">path format: #"D:\FolderName"</param>
public void SaveToXML(string path)
{
try
{
using (StreamWriter sw = new StreamWriter(path+ "\\"+this.GetType().Name+".xml"))
{
ser.Serialize(sw, this);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message );
}
}
public void LoadFromXML(string FullPath)
{
try
{
if (File.Exists(FullPath))
{
using (StreamReader sr= new StreamReader(FullPath))
{
this.InnerList=((XMLCollection<T>) ser.Deserialize(sr)).InnerList ;
}
}
else
{
Console.WriteLine("File not exist....");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message );
}
}
}
CollectionList is derived from it:
public class CollectionList :XMLCollection<Moshakhase>, IList<Moshakhase>, IDisposable
{
public enum SortType
{
Name, ID
}
#region ctor
public CollectionList()
{
}
public CollectionList(Moshakhase item)
{
this.Add(item);
}
public CollectionList(params Moshakhase[] item)
{
InnerList.AddRange(item);
}
#endregion
public override string ToString()
{
string str = this.GetType().Name + ":\r\n";
foreach (Moshakhase item in this)
{
str += string.Format("\t{0}({1})\r\n", item.Name, item.Id);
}
return str;
}
#region Sort
public void sort(SortType type)
{
switch (type)
{
case SortType.Name:
InnerList.Sort();
break;
case SortType.ID:
InnerList.Sort(new IDCompare());
break;
default:
break;
}
}
class IDCompare : IComparer<Moshakhase>
{
public int Compare(Moshakhase x, Moshakhase y)
{
if (x.Id > y.Id)
{
return 1;
}
else if (x.Id < y.Id)
{
return -1;
}
return 0;
}
}
#endregion
#region Ilist
public int IndexOf(Moshakhase item)
{
return InnerList.IndexOf(item);
}
public void Insert(int index, Moshakhase item)
{
InnerList.Insert(index, item);
}
public void RemoveAt(int index)
{
InnerList.RemoveAt(index);
}
public Moshakhase this[int index]
{
get
{
return InnerList[index];
}
set
{
InnerList[index] = value;
}
}
public void Add(Moshakhase item)
{
InnerList.Add(item);
}
public void Clear()
{
InnerList.Clear();
}
public bool Contains(Moshakhase item)
{
return InnerList.Contains(item);
}
public void CopyTo(Moshakhase[] array, int arrayIndex)
{
InnerList.CopyTo(array,arrayIndex );
}
public int Count
{
get { return InnerList.Count ; }
}
public bool IsReadOnly
{
get { throw new NotImplementedException(); }
}
public bool Remove(Moshakhase item)
{
return InnerList.Remove(item);
}
public IEnumerator<Moshakhase> GetEnumerator()
{
return InnerList.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return InnerList.GetEnumerator();
}
#endregion
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
Users is derived from CollectionList :
public class Users : CollectionList
{
public Users()
{
}
public Users(ketabkhune.unique.User user): base(user)
{
}
public Users(params ketabkhune.unique.User[] user):base(user)
{
}
}
I use this code to check it:
Users uList = new Users(new User[] {new User(4,"Kamran"), new User(3,"Sara"), new User(5,"Bahar") });
uList.SaveToXML(#"F:\xml");
when I combined XMLCollection with CollectionList and define CollectionList as a generic class. that error disappeared..
Don't forget blank constructor
[Serializable()]
public class CollectionList<T> : IList<T>
{
private XmlSerializer ser;
private List<T> InnerList = new List<T>();
#region ctor
public CollectionList()
{
ser = new XmlSerializer(this.GetType());
}
public CollectionList(string CollectionName)
{
ser = new XmlSerializer(this.GetType(), new XmlRootAttribute(CollectionName ));
}
....
Change Your Code Where The Line Like Bellow :
ser.Serialize(sw, m_InnerList);

Replacing the return value - from DataPortal to DataTable

public static CustomizeCourseCompletionWithModuleList GetCustomizeCourseCompletionWithModuleList()
{
var cmd = new StoredProcedure
{
CommandText = "CustomizeCourseCompletionWithModuleSelectById",
CommandType = System.Data.CommandType.StoredProcedure
};
cmd.Parameters.Add("#ID", DBNull.Value);
return DataPortal.Fetch<CustomizeCourseCompletionWithModuleList>(cmd);
}
In the end instead of returning DataPortal I want to return DataTable, how should I do this ?
CustomizeCourseCompletionWwithModuleList class :
public class CustomizeCourseCompletionWithModuleList : BusinessListBase<CustomizeCourseCompletionWithModule>
{
#region Business Methods
public CustomizeCourseCompletionWithModule GetItem(int childId)
{
return this.FirstOrDefault(child => child.Id == childId);
}
public override void Remove(int childId)
{
foreach (var child in this.Where(child => child.Id == childId))
{
RemoveChild(child);
break;
}
}
public bool Contains(int childId)
{
return this.Any(child => child.Id == childId);
}
public bool ContainsDeleted(int childId)
{
return DeletedList.Any(child => child.Id == childId && child.IsDeleted);
}
#endregion
StoredProcedure :
public class StoredProcedure : ICloneable
{
private Parameters _parameters = new Parameters();
private string _procName;
public StoredProcedure(string name)
{
_procName = name;
CommandType = System.Data.CommandType.StoredProcedure;
}
public StoredProcedure()
{
CommandType = System.Data.CommandType.StoredProcedure;
}
[DataMember]
public String CommandText
{
get { return _procName; }
set { _procName = value; }
}
[DataMember]
public System.Data.CommandType CommandType { get; set; }
[DataMember]
public string Name
{
get { return _procName; }
set { _procName = value; }
}
[DataMember]
public Parameters Parameters
{
get { return _parameters; }
set { _parameters = value; }
}
#region ICloneable Members
object ICloneable.Clone()
{
return GetClone();
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual object GetClone()
{
return ObjectCloner.Clone(this);
}
#endregion
}
If u need any other information please ask, so you can give me a proper answer.
Thanks in advance.
I'm not sure if this is helpful but I did some digging and I came across this article that talks about using CLSA's ObjectAdapter in order to transform a list into a DataSet. Csla.Data.ObjectAdapter
//Get the a musicians BusinessBaseList
MusiciansList musicians = MusiciansList.GetList();
//Use the ObjectAdapter to transform the list into
//a DataSet
ObjectAdapter adapter = new ObjectAdapter();
DataSet ds = new DataSet();
adapter.Fill(ds, musicians);
//Bind the DataSet to the musician’s
//DropDownList
ddMusicians.DataSource = ds.Tables[0];
ddMusicians.DataTextField = "LastName";
ddMusicians.DataValueField = "Id";
ddMusicians.DataBind();

Class Mapping Error: 'T' must be a non-abstract type with a public parameterless constructor

While mapping class i am getting error 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method.
Below is my SqlReaderBase Class
public abstract class SqlReaderBase<T> : ConnectionProvider
{
#region Abstract Methods
protected abstract string commandText { get; }
protected abstract CommandType commandType { get; }
protected abstract Collection<IDataParameter> GetParameters(IDbCommand command);
**protected abstract MapperBase<T> GetMapper();**
#endregion
#region Non Abstract Methods
/// <summary>
/// Method to Execute Select Queries for Retrieveing List of Result
/// </summary>
/// <returns></returns>
public Collection<T> ExecuteReader()
{
//Collection of Type on which Template is applied
Collection<T> collection = new Collection<T>();
// initializing connection
using (IDbConnection connection = GetConnection())
{
try
{
// creates command for sql operations
IDbCommand command = connection.CreateCommand();
// assign connection to command
command.Connection = connection;
// assign query
command.CommandText = commandText;
//state what type of query is used, text, table or Sp
command.CommandType = commandType;
// retrieves parameter from IDataParameter Collection and assigns it to command object
foreach (IDataParameter param in GetParameters(command))
command.Parameters.Add(param);
// Establishes connection with database server
connection.Open();
// Since it is designed for executing Select statements that will return a list of results
// so we will call command's execute reader method that return a Forward Only reader with
// list of results inside.
using (IDataReader reader = command.ExecuteReader())
{
try
{
// Call to Mapper Class of the template to map the data to its
// respective fields
MapperBase<T> mapper = GetMapper();
collection = mapper.MapAll(reader);
}
catch (Exception ex) // catch exception
{
throw ex; // log errr
}
finally
{
reader.Close();
reader.Dispose();
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
connection.Close();
connection.Dispose();
}
}
return collection;
}
#endregion
}
What I am trying to do is , I am executine some command and filling my class dynamically. The class is given below:
namespace FooZo.Core
{
public class Restaurant
{
#region Private Member Variables
private int _restaurantId = 0;
private string _email = string.Empty;
private string _website = string.Empty;
private string _name = string.Empty;
private string _address = string.Empty;
private string _phone = string.Empty;
private bool _hasMenu = false;
private string _menuImagePath = string.Empty;
private int _cuisine = 0;
private bool _hasBar = false;
private bool _hasHomeDelivery = false;
private bool _hasDineIn = false;
private int _type = 0;
private string _restaurantImagePath = string.Empty;
private string _serviceAvailableTill = string.Empty;
private string _serviceAvailableFrom = string.Empty;
public string Name
{
get { return _name; }
set { _name = value; }
}
public string Address
{
get { return _address; }
set { _address = value; }
}
public int RestaurantId
{
get { return _restaurantId; }
set { _restaurantId = value; }
}
public string Website
{
get { return _website; }
set { _website = value; }
}
public string Email
{
get { return _email; }
set { _email = value; }
}
public string Phone
{
get { return _phone; }
set { _phone = value; }
}
public bool HasMenu
{
get { return _hasMenu; }
set { _hasMenu = value; }
}
public string MenuImagePath
{
get { return _menuImagePath; }
set { _menuImagePath = value; }
}
public string RestaurantImagePath
{
get { return _restaurantImagePath; }
set { _restaurantImagePath = value; }
}
public int Type
{
get { return _type; }
set { _type = value; }
}
public int Cuisine
{
get { return _cuisine; }
set { _cuisine = value; }
}
public bool HasBar
{
get { return _hasBar; }
set { _hasBar = value; }
}
public bool HasHomeDelivery
{
get { return _hasHomeDelivery; }
set { _hasHomeDelivery = value; }
}
public bool HasDineIn
{
get { return _hasDineIn; }
set { _hasDineIn = value; }
}
public string ServiceAvailableFrom
{
get { return _serviceAvailableFrom; }
set { _serviceAvailableFrom = value; }
}
public string ServiceAvailableTill
{
get { return _serviceAvailableTill; }
set { _serviceAvailableTill = value; }
}
#endregion
public Restaurant() { }
}
}
For filling my class properties dynamically i have another class called MapperBase Class with following methods:
public abstract class MapperBase<T> where T : new()
{
protected T Map(IDataRecord record)
{
T instance = new T();
string fieldName;
PropertyInfo[] properties = typeof(T).GetProperties();
for (int i = 0; i < record.FieldCount; i++)
{
fieldName = record.GetName(i);
foreach (PropertyInfo property in properties)
{
if (property.Name == fieldName)
{
property.SetValue(instance, record[i], null);
}
}
}
return instance;
}
public Collection<T> MapAll(IDataReader reader)
{
Collection<T> collection = new Collection<T>();
while (reader.Read())
{
collection.Add(Map(reader));
}
return collection;
}
}
There is another class which inherits the SqlreaderBaseClass called DefaultSearch. Code is below
public class DefaultSearch: SqlReaderBase<Restaurant>
{
protected override string commandText
{
get { return "Select Name from vw_Restaurants"; }
}
protected override CommandType commandType
{
get { return CommandType.Text; }
}
protected override Collection<IDataParameter> GetParameters(IDbCommand command)
{
Collection<IDataParameter> parameters = new Collection<IDataParameter>();
parameters.Clear();
return parameters;
}
protected override MapperBase<Restaurant> GetMapper()
{
MapperBase<Restaurant> mapper = new RMapper();
return mapper;
}
}
But whenever I tried to build , I am getting error 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method. Even T here is Restaurant has a Parameterless Public constructor.
The problem is that you're trying to use the T from SqlReaderBase as the type argument for MapperBase - but you don't have any constraints on that T.
Try changing your SqlReaderBase declaration to this:
public abstract class SqlReaderBase<T> : ConnectionProvider
where T : new()
Here's a shorter example which demonstrates the same issue:
class Foo<T>
{
Bar<T> bar;
}
class Bar<T> where T : new()
{
}
The fix is to change Foo<T>'s declaration to:
class Foo<T> where T : new()
Then the compiler will know that the T from Foo is a valid type argument for Bar.
The constraints must apply to every type in the chain; hence you need:
public abstract class SqlReaderBase<T> : ConnectionProvider where T : new()
Without this, you can't satisfy the constraint for T in:
protected abstract MapperBase<T> GetMapper();
or
MapperBase<T> mapper = GetMapper();
since MapperBase<> is only usable when T has : new()
I had the same issue. I should have read the message before Googling it. I needed to add a parameterless constructor ... :-)
public MyClass() {
//stuff
}

Categories