I'm writing a generic method to put set values on the base class
public class StageOne: DefaultValues
{
//StageOne properties
}
public class DefaultValues
{
public string status { get; set; }
public string message { get; set; }
}
private T SetValue<T>() where T : DefaultValues
{
T.message = "Good Job";
T.status = "Done";
return default(T);
}
I get an error on T.message and T.status; T is type parameter, which is not valid in the given context
I have already Googled it and I can't find my answer - please help.
Thanks.
If you want to set properties of the generic type, then you need an instance of the type. To get an instance we either need to have the caller pass one in as an argument, or create a new one (and if we choose this option, we need to include the new() constraint as well):
First option - have the caller pass in an instance of the type (no need for a return value in this case since the caller already has a reference to the instance we're changing):
private void SetValue<T>(T input) where T : DefaultValues
{
input.message = "Good Job";
input.status = "Done";
}
Second option - create a new instance of the type inside the method (note the added generic constraint, new()):
private T SetValue<T>() where T : DefaultValues, new()
{
T result = new T();
result.message = "Good Job";
result.status = "Done";
return result;
}
Which could be simplified to:
private static T SetValue<T>() where T : DefaultValues, new()
{
return new T {message = "Good Job", status = "Done"};
}
Related
I need to return a genericList templateFields as below from a generic list with code as below:
public interface TestData
{
string field { get; set; }
string fieldName { get; set; }
string type { get; set; }
}
private static IList<T> GETCG<T>(string test, string type) where T : Program.TestData
{
XmlNodeList extractNode = xdoc.SelectNodes(
#".//mediaInstances/mediaInstance/properties/templateFields/templateField", manager);
var nodees = new List<XmlNode>(extractNode.Cast<XmlNode>());
var templateFields = nodees.Cast<XmlNode>().Select(x => new
{
field = (String)x.Attributes["userName"].Value,
fieldName = (String)x.Attributes["name"].Value
.Substring(0, x.Attributes["name"].Value.IndexOf(':')),
type = (String)x.Attributes["name"].Value.Substring(x.Attributes["name"].Value
.IndexOf(':') + 1, 4)
}).ToList();
}
return (T)Convert.ChangeType(templateFields, typeof(T));
I get the following error, on the return:
Object must implement Iconvertible.
I do understand templateFields doesnot implement IConvertible to use ChangeType. What's the best way of returning templateFields
Add new() contraint to T and use the following codee
private static IList<T> GETCG<T>(string test, string type) where T : TestData, new()
{
XmlNodeList extractNode = xdoc.SelectNodes(#".//mediaInstances/mediaInstance/properties/templateFields/templateField", manager);
var nodees = new List<XmlNode>(extractNode.Cast<XmlNode>());
var templateFields = nodees.Cast<XmlNode>().Select(x => new T() //not anonymous type but T object
{
field = x.Attributes["userName"].Value,
fieldName = (string)x.Attributes["name"].Value.Substring(0, x.Attributes["name"].Value.IndexOf(':')),
type = x.Attributes["name"].Value.Substring(x.Attributes["name"].Value.IndexOf(':') + 1, 4)
}).ToList();
return templateFields;
}
I think the problem here is that you're selecting an anonymous type when you do select new { ... }, and then the Convert.ChangeType fails because anonymous types only include public read-only properties, and don't implement IConvertible. Instead, we want to select a new T. But in order to do this, we also have to include a new() constraint on T, which means that T must have a default constructor (so we can create an instance of it).
By doing this, we don't need to convert anything, as we have a List<T> as a result of the Select.
You can also reduce some code by selecting an IEnumerable<XmlNode> in one line, rather than creating a second variable and doing a cast on the first one.
Something like this should work:
private static IList<T> GETCG<T>(string test, string type) where T : TestData, new()
{
IEnumerable<XmlNode> templateFieldNodes = xdoc
.SelectNodes(".//mediaInstances/mediaInstance/properties/templateFields/templateField",
manager)
.Cast<XmlNode>();
return templateFieldNodes.Select(x => new T
{
field = (String)x.Attributes["userName"].Value,
fieldName = (String)x.Attributes["name"].Value
.Substring(0, x.Attributes["name"].Value.IndexOf(':')),
type = (String)x.Attributes["name"].Value.Substring(x.Attributes["name"].Value
.IndexOf(':') + 1, 4)
}).ToList();
}
You declared an interface TestData but didn't declare any type implementing it. You cannot cast any type that just happens to have the same properties by accident to this interface. You must create a class or struct implementing it. Also, with the usual .NET naming conventions interface names start with an upper case I and property names have PascalCase.
With these declarations ...
public interface ITestData
{
string Field { get; set; }
string FieldName { get; set; }
string Type { get; set; }
}
public class TestData : ITestData
{
public string Field { get; set; }
public string FieldName { get; set; }
public string Type { get; set; }
}
You can write
private static IList<ITestData> GETCG(string test, string type)
{
XmlNodeList extractNode = xdoc.SelectNodes(
#".//mediaInstances/mediaInstance/properties/templateFields/templateField", manager);
var nodees = new List<XmlNode>(extractNode.Cast<XmlNode>());
var templateFields = nodees.Cast<XmlNode>().Select(x => (ITestData)new TestData {
Field = (String)x.Attributes["userName"].Value,
FieldName = (String)x.Attributes["name"].Value
.Substring(0, x.Attributes["name"].Value.IndexOf(':')),
Type = (String)x.Attributes["name"].Value.Substring(x.Attributes["name"].Value
.IndexOf(':') + 1, 4)
}).ToList();
return templateFields;
}
Note that the method is not generic. To make .ToList() create a IList<ITestData>, the new data must be casted to the interface (ITestData)new TestData { ... }.
The question is whether you still need the interface, or if you prefer to use the class directly.
If you still want the method to be generic, you must tell it that T must have a default constructor with the new() constraint. And you must call the method with a concrete type. I.e., you cannot call it with the interface, since this one does not have a constructor.
private static IList<T> GETCG<T>(string test, string type)
where T : ITestData, new()
{
...
var templateFields = nodees.Cast<XmlNode>().Select(x => new T {
...
}).ToList();
return templateFields;
}
and call with
IList<TestData> var result = GETCG<TestData>("hello", "world");
Just to clarify, I have this working using dynamic and MakeGenericType. But I cant help but think there is a better way to do this. What I am trying to do is create a "plug-in" loader, using Unity. I will just explain it as I post the code so you can get a sense for what I am doing.
First I'll just post the plug-in itself:
[RegisterAction("MyPlugin", typeof(bool), typeof(MyPlugin))]
public class MyPlugin: IStrategy<bool>
{
public IStrategyResult<bool> Execute(ISerializable info = null)
{
bool result;
try
{
// do stuff
result = true;
}
catch (Exception)
{
result = false;
}
return new StrategyResult<bool>
{
Value = result
};
}
}
Couple things to note here. First is the RegisterActionAttribute:
[AttributeUsage(AttributeTargets.Class)]
public sealed class RegisterActionAttribute : Attribute
{
public StrategyAction StrategyAction { get; }
public RegisterActionAttribute(string actionName, Type targetType, Type returnType, params string[] depdencies)
{
StrategyAction = new StrategyAction
{
Name = actionName,
StrategyType = targetType,
ResponseType = returnType,
Dependencies = depdencies
};
}
}
Then the interfaces:
public interface IStrategy<T>
{
IStrategyResult<T> Execute(ISerializable info = null);
}
public interface IStrategyResult<T>
{
bool IsValid { get; set; }
T Value { get; set; }
}
All fairly straight forward. The goal here is just to attach some meta-data to the class when it is loaded. The loading happens via unity using a wrapper that simply loads the assemblies in the bin directory using a file search pattern and adds it to a singleton class with a collection of StrategyActions. I don't need paste all the unity code here as I know it works and registers and resolves the assemblies.
So now to the meat of the question. I have a function on the singleton that executes actions. These are applied with Unity.Interception HandlerAttributes and passed a string like so (I can post the code for this but I didn't think it was relevant):
[ExecuteAction("MyPlugin")]
The handler calls the following execute function on the singleton class to "execute" functions that are registered (added to the collection).
public dynamic Execute(string action, params object[] parameters)
{
var strategyAction = _registeredActions.FirstOrDefault(a => a.Name == action);
if (strategyAction == null)
return null;
var type = typeof (IStrategy<>);
var generic = type.MakeGenericType(strategyAction.StrategyType);
var returnType = typeof (IStrategyResult<>);
var genericReturn = returnType.MakeGenericType(strategyAction.ResponseType);
var instance = UnityManager.Container.Resolve(generic, strategyAction.Name);
var method = instance.GetType().GetMethod("Execute");
return method.Invoke(instance, parameters);
}
This execute is wrapped in an enumerator call which returns a collection of results, which sorts to manage dependencies and what not (see below). These values are referenced by the caller using the Value property of ISTrategyResult{T} to do various things defined by other business rules.
public List<dynamic> ExecuteQueuedActions()
{
var results = new List<dynamic>();
var actions = _queuedActions.AsQueryable();
var sortedActions = TopologicalSort.Sort(actions, action => action.Dependencies, action => action.Name);
foreach(var strategyAction in sortedActions)
{
_queuedActions.Remove(strategyAction);
results.Add(Execute(strategyAction.Name));
}
return results;
}
Now mind you, this works, and I get the return type that is specified by the plugins RegisterAction attribute. As you can see I am capturing the Type of the plugin and the return type. I am using the "generic" variable to resolve the type with unity through the use of MakeGenericType, which works fine. I am also creating a generic representing the return type based on the type from the collection.
What I don't like here is having to use dynamic to return this value to a function. I can't figure out a way to return this as a IStrategyResult{T} because obviously the caller to "dynamic Execute(..." can not, at run-time, imply return type of the function. I mulled around with making the call to Execute with a MakeGenericMethod call as I actually have the expected type the StrategyAction. It would be cool if I could some how figure out away to return a strongly typed result of IStrategyResult{T} while determining the type of T during the call.
I do understand why I cannot do this with my current implementation I am just trying to find a way to wrap all this functionality without using dynamic. And was hoping somebody could provide some advice that might be useful. If that means wrapping this with other calls to non-generic classes or something like that, that would be fine as well if that is the only solution.
You need a more sweeping refactor than just figure out how to call your plugin.
There's no need for the [RegisterAction] attribute to hold targetType and returnType, these parameters to the attribute can easily get out of sync with code, making them a potential hole to fall into.
Then think from the other side of your setup: how do you consume the data, what do you do with your IStrategyResult<> - does it really have to be generic or there is a specific way you could encapsulate the type of results? I can't quite imagine a plugin system that returns "anything" to the host. The hint is really in your dynamic Execute(...) - your parameters and your result have both lost their strong typing, showing you that strong-typing the plugin is not helping with anything. Just use object or - better - make a StrategyResult class instead of the current interface and provide whatever properties are necessary there (I've added a few frivolous examples), such as:
public class StrategyResult{
public object Result{get;set;}
public Type ResultType {get;set;}
// frivolous examples
public bool IsError {get;set;}
public string ErrorMessage {get;set;}
// really off-the-wall example
public Func<StrategyHostContext,bool> ApplyResultToContext {get;set;}
public StrategyResult(){
}
public StrategyResult FromStrategy(IStrategy strategy){
return new StrategyResult{
ResultType = strategy.ResultType
}
}
public StrategyResult FromStrategyExecute(IStrategy strategy, ISerializable info = null){
var result = FromStrategy(strategy);
try{
strategy.Execute(info);
} catch (Exception x){
result.IsError = true;
result.ErrorMessage = x.Message;
}
}
}
Then your IStrategy becomes:
public interface IStrategy{
Type ResultType {get;}
void Initialize(SomeContextClassMaybe context);
StrategyResult Execute(ISerializable info = null);
}
You can also change your attribute to make it more efficient to load large plugins:
[AttributeUsage(AttributeTargets.Assembly)]
public sealed class AddinStrategyAttribute : Attribute
{
public Type StategyType {get; private set;}
public AddinStrategyAttribute(Type strategyType){
StrategyType = strategyType;
}
}
... and use the attribute like so:
[assembly:AddinStrategy(typeof(BoolStrategy))] // note it's outside the namespace
namespace MyNamespace{
public class BoolStrategy: IStrategy{
public Type ResultType { get{ return typeof(bool);}}
public void Initialize (SomeContextClassMaybe context){
}
public StrategyResult Execute(ISerializable info = null){
return StrategyResult.FromStrategyExecute(this,info);
}
}
}
Assuming that the caller of ExecuteActions does not have any knowledge about the T in any of the plugins or results and must work with dynamic or object anyway, then the following may work:
Infrastructure:
public interface IStrategy
{
IStrategyResult Execute(ISerializable info = null);
}
public interface IStrategyResult
{
bool IsValid { get; }
dynamic Value { get; }
}
public class StrategyResult<T> : IStrategyResult
{
public T Value { get; private set; }
public StrategyResult(T value) { this.Value = value; }
public bool IsValid { get { throw new NotImplementedException(); } }
dynamic IStrategyResult.Value { get { return this.Value; } }
}
[AttributeUsage(AttributeTargets.Class)]
public sealed class RegisterActionAttribute : Attribute
{
public List<string> Dependencies { get; private set; }
public RegisterActionAttribute(params string[] depdencies)
{
this.Dependencies = new List<string>(depdencies);
}
}
public class StrategyAction
{
public string Name;
public List<string> Dependencies;
}
public abstract class BasePlugin<T> : IStrategy
{
public IStrategyResult Execute(ISerializable info = null)
{
return new StrategyResult<T>(this.execute(info));
}
protected abstract T execute(ISerializable info);
}
Example plugin:
[RegisterAction]
public class MyFirstPlugin: BasePlugin<bool>
{
protected override bool execute(ISerializable info = null)
{
try
{
// do stuff
return true;
}
catch (Exception)
{
return false;
}
}
}
[RegisterAction("MyFirstPlugin")]
public class MySecondPlugin: BasePlugin<string>
{
protected override string execute(ISerializable info = null)
{
try
{
// do stuff
return "success";
}
catch (Exception)
{
return "failed";
}
}
}
Example execution engine:
public class Engine
{
public List<StrategyAction> registeredActions = new List<StrategyAction>();
private List<StrategyAction> queuedActions = new List<StrategyAction>();
public IStrategyResult Execute(string action, ISerializable info = null)
{
if (this.registeredActions.FirstOrDefault(a=>a.Name == action) == null) return null;
// This code did not appear to be used anyway
//var returnType = typeof (IStrategyResult<>); //var genericReturn = returnType.MakeGenericType(strategyAction.ResponseType);
var instance = (IStrategy) UnityManager.Container.Resolve(typeof(IStrategy), action);
return instance.Execute(info);
}
public List<IStrategyResult> ExecuteQueuedActions()
{
var results = new List<IStrategyResult>();
var actions = this.queuedActions.AsQueryable();
var sortedActions = TopologicalSort.Sort(actions, action => action.Dependencies, action => action.Name);
foreach(var strategyAction in sortedActions)
{
this.queuedActions.Remove(strategyAction);
results.Add(Execute(strategyAction.Name));
}
return results;
}
}
Note that when the plugins are loaded, the RegisterActionAttribute information along with the name of the plugin type loaded need to be combined into a StrategyAction instance and loaded into the registeredActions field of the engine.
The above allows the plugins to work with strong types but still allows the engine to deal with a variety of types. If you need the engine to work with more strongly typed data, then please provide an example of how the callers of ExecuteQueuedActions are expected to work with the results from ExecuteQueuedActions.
You got into this pickle by giving your RegisterActionAttribute constructor the returnType argument. Since you have only one Execute() method, you are forced to deal with the fact that the return type can be different types.
Using dynamic is about as good as it gets. You can make Execute() generic but then you'll have to deal with a mismatch between its type parameter and the attribute's ResponseType. Not one that the compiler can catch, this fails at runtime. It isn't generic.
Frankly, this strongly sounds like one flexibility too many. At the risk of interpreting the point of having a return type incorrectly, the outcome of a "registration action" is rather boolean. It worked or it didn't work. And is in fact the way you implemented it, your first plugin snippet does return bool.
With very high odds that you should not use bool either. Failure ought to make a bang, you'd throw an exception.
Why not define a super interface IStrategyResult like this:
interface IStrategyResult
{
Type ReturnType { get; }
}
interface IStrategyResult<T> : IStrategyResult
{
// your code here
}
Then define your execute like this:
public IStrategyResult Execute(string action, params object[] parameters)
And have your StrategyResult : IStrategyResult<T> class set the property to return typeof(T)
By convention you could assume (or enforce using inheritance on an abstract StrategyResult<T> : IStrategyResult<T> class) the T to be the same as the ReturnType property of the non-generic IStrategyResult interface.
public class Address
{...}
public class Object1
{
public Address Address {get;set;}
}
public class Object2
{
public Address Address {get;set;}
}
public UpdateAddress(Address address)
{
address = new Address();
}
//calling
var obj1 = new Object1();
UpdateAddress(obj1.Address);
//obj1.Address IS NULL
I cannot have my 2 classes inherit from a baseclass that has Address property (long story)
I was under the impression that when passing objects into methods they are by reference and my obj1.Address will have a new one and not be null if i am passing that property into a method.
If my assumption is wrong and it seems to be about object not being passed by reference in this instance.
How can i have a generic method that I can update a property that is the same across all my objects (I know I can return a new address object but I prefer to be passed in instead of returning)
Can this also be done by passing T<>?
UPDATE - Actual Code
Calling the methods
bool isVendorIdFromModel = UpdateVendor(entity.ExpenseVendor, entity.ExpenseVendorId, model, isNew, context);
if (isVendorIdFromModel)
{
entity.ExpenseVendorId = model.VendorId;
}
private static bool UpdateVendor(ExpenseVendor vendor, int? entityVendorId, ExpenseBaseModel model, bool isNew, ELMSContext context)
{
if (model.VendorId.HasValue)
{
if (entityVendorId != model.VendorId)
{
return true;
}
UpdateVendorInfo(model, vendor);
}
else
{
if (isNew && !string.IsNullOrEmpty(model.VendorName))
{
vendor = new ExpenseVendor
{
...
};
context.ExpenseVendors.Add(vendor);
}
if (vendor != null)
{
UpdateVendorInfo(model, vendor);
}
}
return false;
}
private static void UpdateVendorInfo(ExpenseBaseModel model, ExpenseVendor vendor)
{
vendor.Name = model.VendorName;
vendor.Address1 = model.Address1;
vendor.Address2 = model.Address2;
vendor.City = model.City;
vendor.PostalCode = model.PostalCode?.Replace(" ", string.Empty);
vendor.ProvinceId = model.ProvinceId;
}
Usual options:
shared base class (if you can change code and class hierarchy)
shared interface (if you can can change code, but no class hierarchy)
pass lambdas for getter/setter
use reflection and set by name
Since it sounds like you can't change the source lambda option may be the easiest. Following is option to "set" (when you replace whole object):
public void UpdateAddress(Action<Address> addressSetter)
{
addressSetter(new Address());
}
//calling
var obj1 = new Object1();
UpdateAddress(address => obj1.Address = address);
If you need to set properties of such object instead of replacing - pass get delegate:
public void UpdateAddress(Func<Address> addressGetter)
{
addressGetter().Street = "Dark alley";
}
UpdateAddress(address => obj1.Address);
Or use both. You can even combine them into helper class so it look close to properties (check out adapter pattern.
Note: generics not going to help you unless you can add common interface (but in that case you probably don't need generics at all).
If UpdateAddress only returns an address then change it to:
public Address UpdateAddress()
{
// set up address
return address;
}
var obj1 = new Object1();
obj1.Address = UpdateAddress();
Passing by reference and manipulating the contents of a parameter is a code smell. Write methods that return values and set the property that way.
I am trying to figure out something with c# code, and I'm not 100% sure if it is possible, but I am trying to implement search functionality for several classes which is streamlined and overall easy to develop for. Right now I have the following code:
[DataContract(IsReference = true), Serializable]
public class ClassSearch
{
[DataMember]
public string Name { get; set; }
[DataMember]
public object Value { get; set; }
public override string ToString()
{
return String.Format("{0} = {1}", Name, Value);
}
... // additional logic
}
However, I would like to include strong typing for the object value so that it only can be set to the property that is passed in, I guess like similar (hypothetical, not sure if this would work)
[DataContract(IsReference = true), Serializable]
public class ClassSearch<TProperty>
{
[DataMember]
public TProperty Property {get; set; }
public override string ToString()
{
return String.Format("{0} = '{1}'", Property.Name, Property);
}
... // additional logic
}
public class MainClass
{
public void Execute()
{
SomeClass someClass = new Class{
Property = "Value";
};
ClassSearch search = new ClassSearch<SomeClass.Property>{
Property = someClass.Property
};
var retString = search.ToString(); // Returns "Property = 'Value'"
}
}
It seems you are trying to create a WCF service to be able to pass any type you like.
First of all, this is not WSDL-friendly. All WCF services needs to be able to be exposed in WSDL. WSDL is all about well-defined contracts hence the types need be all defined. So that generic approach would not work - mainly because of WSDL. Having said that, you still can use generics but then you have to use KnownType and actually define all the types possible - which for me defeats the object.
Yet, one thing you can do is to serialize the object yourself and pass around with its type name across the wire. On the other side, you can pick it up deserialize.
So something along the line of:
// NOTE: Not meant for production!
[DataContract]
public class GenericWcfPayload
{
[DataMember]
public byte[] Payload {get; set;}
[DataMember]
public string TypeName {get; set;}
}
If there are no easier answers I would try it with this one.
You could use expressions like so:
// Sample object with a property.
SomeClass someClass = new SomeClass{Property = "Value"};
// Create the member expression.
Expression<Func<object /*prop owner object*/, object/*prop value*/>> e =
owner => ((SomeClass)owner).Property;
// Get property name by analyzing expression.
string propName = ((MemberExpression)e.Body).Member.Name;
// Get property value by compiling and running expression.
object propValue = e.Compile().Invoke(someClass);
You hand over your property by the member expression owner => ((SomeClass)owner).Property. This expression contains both information you need: property name and property value. The last two lines show you how to get name and value.
Following a larger example:
class MainClass
{
public static void Execute()
{
SomeClass someClass = new SomeClass{
Property = "Value"
};
var search = new ClassSearch(s => ((SomeClass)s).Property);
Console.Out.WriteLine("{0} = '{1}'", search.Property.Name, search.Property.GetValue(someClass));
}
}
class Reflector
{
public static string GetPropertyName(Expression<Func<object, object>> e)
{
if (e.Body.NodeType != ExpressionType.MemberAccess)
{
throw new ArgumentException("Wrong expression!");
}
MemberExpression me = ((MemberExpression) e.Body);
return me.Member.Name;
}
}
class ClassSearch
{
public ClassSearch(Expression<Func<object, object>> e)
{
Property = new PropertyNameAndValue(e);
}
public PropertyNameAndValue Property { get; private set; }
public override string ToString()
{
return String.Format("{0} = '{1}'", Property.Name, Property);
}
}
class PropertyNameAndValue
{
private readonly Func<object, object> _func;
public PropertyNameAndValue(Expression<Func<object, object>> e)
{
_func = e.Compile();
Name = Reflector.GetPropertyName(e);
}
public object GetValue(object propOwner)
{
return _func.Invoke(propOwner);
}
public string Name { get; private set; }
}
class SomeClass
{
public string Property { get; set; }
}
The main part of that example is the method Reflector.GetPropertyName(...) that returns the name of a property within an expression. I.e. Reflector.GetPropertyName(s => ((SomeClass)s).Property) would return "Property".
The advantage is: This is type-safe because in new ClassSearch(s => s.Property) compiling would end with an error if SomeClass would not have a property 'Property'.
The disadvantage is: This is not type-safe because if you write e.g. new ClassSearch(s => s.Method()) and there would be a method 'Method' then there would be no compile error but a runtime error.
EDIT I updated my question for completeness.
I have incoming REST calls from an iPHone client. It is meant to consume type-specific objects
in response to generic requests. For example:
http://localhost:81/dashboard/group/id/0
returns data from the Regions type
http://localhost:81/dashboard/group/id/1
returns data from the Customers type
http://localhost:81/dashboard/group/id/2
returns data from the Users type
and so on.
The WCF Dashboard.svc service exposes a base method GetGroupById
which I use to determine and return the type-specific response:
public class Dashboard : GroupBase, Contracts.IDashboardService
{
private string name = String.Empty;
public Dashboard() : base()
{
if (!ServiceSecurityContext.Current.PrimaryIdentity.IsAuthenticated)
throw new WebException("Unauthorized: Class: Dashboard, Method: Dashboard()",
System.Net.HttpStatusCode.Forbidden);
name = ServiceSecurityContext.Current.PrimaryIdentity.Name;
}
public override System.IO.Stream GetGroupById(string id)
{
return base.GetGroupById(id);
}
}
Now, inside my abstract base class the GetGroupById has a switch/case statement that populates
and returns unique data transfer objects based on the corresponding groupid parameter:
public abstract class GroupBase
{
protected GroupBase () { }
public virtual Stream GetGroupById(string id)
{
// I have tried assigning response to null or, in this case,
// assigning it to a random service object. I have also tried
// IObjectFactory response; The last fails at compile-time and
// the other two always produce null
IObjectFactory response =
ObjectFactory<IObjectFactory, UserService>.Create();
var groupId = System.Convert.ToInt32(id);
var serializer = new JavaScriptSerializer();
byte[] bytes = null;
var message = String.Empty;
try
{
switch (groupId)
{
case 0: // regions
response = ObjectFactory<IObjectFactory, RegionService>.Create();
break;
case 1: // customers
response = ObjectFactory<IObjectFactory, CustomerService>.Create();
break;
case 2: // users
response = ObjectFactory<IObjectFactory, UserService>.Create();
break;
}
}
catch (EngageException oops)
{
message = oops.Message;
}
bytes = Encoding.UTF8.GetBytes(serializer.Serialize(response));
return new MemoryStream(bytes);
}
}
A customer ObjectFactory class is used to create the type-specific object:
public static class ObjectFactory where T : F, new()
{
public static F Create()
{
return new T();
}
}
WHERE I AM HAVING PROBLEMS IS what is going on under the hood of my ObjectFactory. I am always
getting ** null ** back. For example, consider the following REST HTTP GET:
http://localhost:81/dashboard/group/id/2
The above command is asking for a JSON string of all Users in the database. Accordingly, the
UserService class is passed into the ObjectFactory method.
public class UserService : IObjectFactory
{
DomainObjectsDto IObjectFactory.Children
{
get
{
return new Contracts.DomainObjectsDto(UserRepository
.GetAllUsers().Select
(p => new Contracts.DomainObjectDto
{
Title = GroupTypes.Customer.ToString(),
Id = p.CustomerId.ToString(),
Type = p.GetType().ToString()
}));
}
}
string IObjectFactory.Method
{
get;
set;
}
string IObjectFactory.Status
{
get;
set;
}
etc...
And, the readonly Get property gets data from the UserRepository, populates the Data Transfer Object
(illustrated below)
[DataContract]
public class DomainObjectDto
{
[DataMember]
public string Title { get; set; }
[DataMember]
public string Id { get; set; }
[DataMember]
public string Type { get; set; }
}
[CollectionDataContract]
public class DomainObjectsDto : List<DomainObjectDto>
{
public DomainObjectsDto() { }
public DomainObjectsDto(IEnumerable<DomainObjectDto> source) : base(source) { }
}
And should return the serialized JSON string of User data to the client. But, my generic type T in my object factory class is always null:
public static F Create()
{
return new T(); // <-- always null!
}
Any ideas??
Hard to tell without seeing the invocation of your factory in context, but my gut feel is that groupId is not in the switch range and thus you are getting the null you defaulted it to. I would add a default case and throw an out of range exception and see if that's your problem.
It's a good idea to add default cases to your switch statements, like:
default:
throw new Exception( "groupId " + groupId + " not found" );
Change the line IObjectFactory response = null; to remove the default, i.e. IObjectFactory response;. Now the compiler will tell you if there is a branch that doesn't assign it (of course, it can't tell you if you assign to null somehow). Note also that there are at least 2 ways of getting null from a new (etc), but these are edge cases - I doubt they are contributing (mentioned for completeness only).