Im just starting with generics and was wondering how I can access T of the class in a class method? Lets take some code to explain better what I want to do:
public class RegisterResult<T> where T : IRegisterable
{
public bool Success { get; set; }
public string Entity { get; set; }
public string ErrorMessage { get; set; }
//Want to avoid this, by using generics:
/*public static RegisterResult UserSuccess = new RegisterResult(true, "User", "");
public static RegisterResult DeviceSuccess = new RegisterResult(true, "Device", "");
public static RegisterResult DeviceDataSucces = new RegisterResult(true, "DeviceData", "");*/
public RegisterResult(bool success, string errmsg)
{
this.Success = success;
//The following line does not work, so how can I reach that?
this.Entity = T.GetType().Name;
this.ErrorMessage = errmsg;
}
}
Thank you very much for all helpful and well meant answers!
UPDATE: Errormessage from Visual Studio
"T" is "type Parameter" and not valid in given context
Simple as this:
this.Entity = typeof(T).Name;
Related
I had a question with regards to custom authorization for AWS API Gateway using a lambda coded in C#. In the documentation for AWS Lambdas, the function signature is as follows:
returnType handler-name(inputType input, ILambdaContext context) {
...
}
The inputType and returnType need to be specified for the function handler. For custom authorization in API Gateway, what should the inputType and returnTypes be? Thanks in advance.
You can opt for a strongly-typed approach without inventing custom classes that need to follow the required schema.
Use Nuget package:
Amazon.Lambda.APIGatewayEvents
Input schema:
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-input.html
Output schema:
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html
Your function prototype can then resemble:
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
public class Function
{
public APIGatewayCustomAuthorizerResponse FunctionHandler(APIGatewayCustomAuthorizerRequest input, ILambdaContext context)
{
bool ok = false;
// authorization logic here...
if(input.AuthorizationToken == "up-down-left-right-a-b-select-start")
{
ok = true;
}
return new APIGatewayCustomAuthorizerResponse
{
PrincipalID = "***",//principal info here...
UsageIdentifierKey = "***",//usage identifier here (optional)
PolicyDocument = new APIGatewayCustomAuthorizerPolicy
{
Version = "2012-10-17",
Statement = new List<APIGatewayCustomAuthorizerPolicy.IAMPolicyStatement>() {
new APIGatewayCustomAuthorizerPolicy.IAMPolicyStatement
{
Action = new HashSet<string>(){"execute-api:Invoke"},
Effect = ok ? "Allow" : "Deny",
Resource = new HashSet<string>(){ "***" } // resource arn here
}
},
}
};
}
}
I thought I would elaborate this a bit. This uses part of what was done here as well as tried to make it like the example they give us here.
http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html
I am not sure if it needs to be async or not? I didn't and this seemed to work pretty well for a basic start.
public class Authorize
{
public Authorize() { }
public AuthPolicy AuthorizeHandler(TokenAuthorizerContext request, ILambdaContext context)
{
var token = request.AuthorizationToken;
switch (token.ToLower())
{
case "allow":
return generatePolicy("user", "Allow", request.MethodArn);
}
return null;
}
private AuthPolicy generatePolicy(string principalId, string effect, string resource)
{
AuthPolicy authResponse = new AuthPolicy();
authResponse.policyDocument = new PolicyDocument();
authResponse.policyDocument.Version = "2012-10-17";// default version
authResponse.policyDocument.Statement = new Statement[1];
Statement statementOne = new Statement();
statementOne.Action = "execute-api:Invoke"; // default action
statementOne.Effect = effect;
statementOne.Resource = resource;
authResponse.policyDocument.Statement[0] = statementOne;
return authResponse;
}
}
public class TokenAuthorizerContext
{
public string Type { get; set; }
public string AuthorizationToken { get; set; }
public string MethodArn { get; set; }
}
public class AuthPolicy
{
public PolicyDocument policyDocument { get; set; }
public string principalId { get; set; }
}
public class PolicyDocument
{
public string Version { get; set; }
public Statement[] Statement { get; set; }
}
public class Statement
{
public string Action { get; set; }
public string Effect { get; set; }
public string Resource { get; set; }
}
I wanted to post the solution that I used that worked for me. Thanks to Josh Maag for pointing me in the right direction. Basically, I created a few simple classes:
public class TokenAuthorizerContext
{
public string Type { get; set; }
public string AuthorizationToken { get; set; }
public string MethodArn { get; set; }
}
public class AuthPolicy
{
public PolicyDocument policyDocument { get; set; }
public string principalId { get; set; }
}
public class PolicyDocument
{
public string Version { get; set; }
public Statement[] Statement { get; set; }
}
public class Statement
{
public string Action { get; set; }
public string Effect { get; set; }
public string Resource { get; set; }
}
```
With the above classes created, the signature to my handler is:
public async Task<AuthPolicy> FunctionHandler(TokenAuthorizerContext request, ILambdaContext context)
You should really take a look at the following link and try to follow it through. The full tutorial is written using Python, so if you're unfamiliar with it, just do your best to follow along and read the full walk-through, but this link will explain the C# portion:
http://docs.aws.amazon.com/lambda/latest/dg/get-started-step5-optional.html
Essentially, the string:
returnType handler-name(inputType input, ILambdaContext context) {
Would be something like this (copied from the AWS page):
public string MyHandler(int count, ILambdaContext context) { ... }
public is added as a scope modifier, the returnType the developer has chosen is string the handler-name is MyHandler and the inputType is int
I'm trying to learn how to use the 'where' in Generic, I seem to have it working but I not sure if how I have done it is the correct way.
Currently I have in a class library:
public class NewMembersViewModel
{
public NewMembersViewModel()
{
Id = Guid.NewGuid().ToString();
}
[Display(Name = "Username")]
[RemoteUsernameValidation("IsUserNameTaken", "Register", ErrorMessage = "Username already taken")]
public string MemberUsername { get; set; }
[Display(Name = "Password")]
public string MemberPassword { get; set; }
[Display(Name = "Email")]
[RemoteEmailValidation("IsEmailTaken", "Register", ErrorMessage = "Email already in use")]
public string MemberEmail { get; set; }
[Display(Name = "Mobile Number")]
[RemoteMobileValidation("IsMobileTaken", "Register", ErrorMessage = "Mobile Number already in use")]
public string MemberMobile { get; set; }
[Display(Name = "Forename")]
public string MemberForename { get; set; }
[Display(Name = "Surname")]
public string MemberSurname { get; set; }
public string Id { get; set; }
public int VerificationCode { get; set; }
}
And
public static class SqlDatabaseMethods<T> where T : NewMembersViewModel
{
public static bool LoginUser(T member)
{
var p = member.MemberEmail;
return true;
}
public static bool AddNewMember(T member)
{
var name = member.MemberForename;
return true;
}
}
Then in my MVC app I have:
bool name = SqlDatabaseMethods<NewMembersViewModel>.AddNewMember(model);
if (name)
{
var test = "works";
}
This does work, can anyone tell me whether I doing it correctly, as all examples I have seen appear to be console apps
Generics make sense when you need have some functionality which is common across multiple classes. In this case where clause defines what the constraints of your generic type are. In such case generic methods help to re-use functionality.
In your case it doesn't seem that SqlDatabaseMethods<T> could be re-used more than once, as model NewMembersViewModel seems to be very specific and hardly re-usable elsewhere.
In your code you are using generics correctly, but in my opinion you don't need generics here at all. You could just as easily use the following code without the overhead of generics:
public static class SqlDatabaseMethods
{
public static bool LoginUser(NewMembersViewModel member)
{
var p = member.MemberEmail;
return true;
}
public static bool AddNewMember(NewMembersViewModel member)
{
var name = member.MemberForename;
return true;
}
}
And then call the method like this:
bool name = SqlDatabaseMethods.AddNewMember(model);
if (name)
{
var test = "works";
}
I'm experimenting with the Neo4jClient in C# and am stuck at the following error:
The best overloaded method match for 'Neo4jClient.IGraphClient.CreateRelationship(Neo4jClient.NodeReference, GraphDB.PrecedesRelationshipo)' has some invalid arguments.
This error is for the line with the following code:
client.CreateRelationship<Process,PrecedesRelationship>(prevProcess, new PrecedesRelationship(currProcess, new PrecedesData(product, isOptional)));
Here, prevProcess and currProcess are both of type Neo4jClient.NodeReference. Actually, I generate the nodes and store their NodeReference values in a dictionary, so that I can easily look them up. The nodes are created just fine.
Below are my classes:
public class Process
{
public string Name { get; set; }
}
,
public class PrecedesData
{
public string Name { get; set; }
public bool IsOptional { get; set; }
public PrecedesData()
{ }
public PrecedesData(string name)
{
this.Name = name;
this.IsOptional = false;
}
public PrecedesData(string name, bool isOptional)
{
this.Name = name;
this.IsOptional = IsOptional;
}
}
and
public class PrecedesRelationship : Relationship<PrecedesData>, IRelationshipAllowingSourceNode<Process>,
IRelationshipAllowingTargetNode<Process>
{
public static readonly string TypeKey = "PRECEDES";
public PrecedesRelationship(NodeReference targetNode, PrecedesData data)
: base(targetNode, data)
{ }
public override string RelationshipTypeKey
{
get { return TypeKey; }
}
}
When I leave out the types in CreateRelationship I get the error that the compiler cannot infer the types.
I looked at the examples on the Neo4jClient Wiki and I thought I got it right but I seem to be mistaken.
What am I missing here?
You should be using Cypher, as the REST API is increasingly legacy. Really, anything non-Cypher is becoming legacy.
client.Cypher
.Start(new { prevProcess, currProcess })
.CreateUnique("prevProcess-[:PRECEDES {precedes}]->currProcess")
.WithParams(new { precedes = new PrecedesData(product, isOptional) })
.ExecuteWithoutResults();
Then, you don't need any relationship classes either.
Also, if you remove the excess constructors, you can shorten the entire code sample down to just this:
public class PrecedesData
{
public string Name { get; set; }
public bool IsOptional { get; set; }
}
client.Cypher
.Start(new { prevProcess, currProcess })
.CreateUnique("prevProcess-[:PRECEDES {precedes}]->currProcess")
.WithParams(new { precedes = new PrecedesData { Name = product, IsOptional = isOptional } })
.ExecuteWithoutResults();
I've got this piece of code to create new objects in a generic way:
var user = User.Create<User>(c => c.Name = "321X");
What I don't like about it is the fact I need to pass the 'generic notation' <T> for every create call. After all I create an object that I'm already referring to...
The code behind this current functionality is:
public class User : CreateBase
{
public string Name { get; set; }
}
public abstract class CreateBase
{
public DateTime CreateDate { get; set; }
public Guid Guid { get; set; }
public static T Create<T>(Action<T> init) where T : CreateBase, new()
{
T obj = new T();
obj.Guid = Guid.NewGuid();
obj.DateTime = DateTime.Now;
init(obj);
return obj;
}
}
Is it possible (and how) to refactor my code to this, to create an object?
var user = User.Create(c => c.Name = "321X");
Thanks!
Define the generic argument on the class level:
public abstract class CreateBase<T> where T : CreateBase<T> , new()
{
public static T Create(Action<T> init)
{
//...
}
}
public class User : CreateBase<User>
{
public string Name { get; set; }
}
Then you can write var user = User.Create(c => c.Name = "321X");
Otherwise the compiler cannot infer the type for your Create method without specifying the type argument.
You were not very far. Try this modification:
public abstract class CreateBase<T> where T : CreateBase<T> , new()
{
public DateTime CreateDate { get; set; }
public Guid Guid { get; set; }
public static T Create(Action<T> init)
{
T obj = new T();
obj.Guid = Guid.NewGuid();
obj.CreateDate = DateTime.Now;
init(obj);
return obj;
}
}
public class User : CreateBase<User>
{
public string Name { get; set; }
}
EDIT: Updated the code after I tested it on my local environment. It works now.
You are doing it the wrong way. Instead of getting rid of the generic argument, get rid of (needlessly) saying User.. Instead:
CreateBase.Create<User>(...)
No more redundancies.
Besides that, calling a static member of the base class through a derived class is an anti-pattern.
A better approach would be to include this functionality in the constructor of the base class (I call it ModelBase)
public abstract class ModelBase
{
public DateTime CreateDate { get; private set; }
public Guid Guid { get; private set; }
public ModelBase()
{
Guid = Guid.NewGuid();
DateTime = DateTime.Now;
}
}
public User : ModelBase
{
public User()
: base()
{
}
public User(string name)
: base()
{
Name = name
}
public string Name { get; set; }
}
Creating a user the standard way will initialize the Guid and date automatically
var user = new User { Name = "xy };
EDIT
I added a second constructor with a name parameter. I you want to force the initialization of the name, drop the first parameterless constructor.
var user = new User("xy");
If you really uncomfortable with that sintax (I, honestly, don't see much problem here)
you can do the following:
public class User : CreateBase
{
public string Name { get; set; }
public static User Create(Action<User> a)
{
return Create<User>(a); //CALL BASE CLASS GENERIC FUNCTION
}
}
After you can call it in a way you would like to do that :
var user = User.Create(c => c.Name = "321X");
I have two C# classes that have many of the same properties (by name and type). I want to be able to copy all non-null values from an instance of Defect into an instance of DefectViewModel. I was hoping to do it with reflection, using GetType().GetProperties(). I tried the following:
var defect = new Defect();
var defectViewModel = new DefectViewModel();
PropertyInfo[] defectProperties = defect.GetType().GetProperties();
IEnumerable<string> viewModelPropertyNames =
defectViewModel.GetType().GetProperties().Select(property => property.Name);
IEnumerable<PropertyInfo> propertiesToCopy =
defectProperties.Where(defectProperty =>
viewModelPropertyNames.Contains(defectProperty.Name)
);
foreach (PropertyInfo defectProperty in propertiesToCopy)
{
var defectValue = defectProperty.GetValue(defect, null) as string;
if (null == defectValue)
{
continue;
}
// "System.Reflection.TargetException: Object does not match target type":
defectProperty.SetValue(viewModel, defectValue, null);
}
What would be the best way to do this? Should I maintain separate lists of Defect properties and DefectViewModel properties so that I can do viewModelProperty.SetValue(viewModel, defectValue, null)?
Edit: thanks to both Jordão's and Dave's answers, I chose AutoMapper. DefectViewModel is in a WPF application, so I added the following App constructor:
public App()
{
Mapper.CreateMap<Defect, DefectViewModel>()
.ForMember("PropertyOnlyInViewModel", options => options.Ignore())
.ForMember("AnotherPropertyOnlyInViewModel", options => options.Ignore())
.ForAllMembers(memberConfigExpr =>
memberConfigExpr.Condition(resContext =>
resContext.SourceType.Equals(typeof(string)) &&
!resContext.IsSourceValueNull
)
);
}
Then, instead of all that PropertyInfo business, I just have the following line:
var defect = new Defect();
var defectViewModel = new DefectViewModel();
Mapper.Map<Defect, DefectViewModel>(defect, defectViewModel);
Take a look at AutoMapper.
There are frameworks for this, the one I know of is Automapper:
http://automapper.codeplex.com/
http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/01/22/automapper-the-object-object-mapper.aspx
Replace your erroneous line with this:
PropertyInfo targetProperty = defectViewModel.GetType().GetProperty(defectProperty.Name);
targetProperty.SetValue(viewModel, defectValue, null);
Your posted code is attempting to set a Defect-tied property on a DefectViewModel object.
In terms of organizing the code, if you don't want an external library like AutoMapper, you can use a mixin-like scheme to separate the code out like this:
class Program {
static void Main(string[] args) {
var d = new Defect() { Category = "bug", Status = "open" };
var m = new DefectViewModel();
m.CopyPropertiesFrom(d);
Console.WriteLine("{0}, {1}", m.Category, m.Status);
}
}
// compositions
class Defect : MPropertyGettable {
public string Category { get; set; }
public string Status { get; set; }
// ...
}
class DefectViewModel : MPropertySettable {
public string Category { get; set; }
public string Status { get; set; }
// ...
}
// quasi-mixins
public interface MPropertyEnumerable { }
public static class PropertyEnumerable {
public static IEnumerable<string> GetProperties(this MPropertyEnumerable self) {
return self.GetType().GetProperties().Select(property => property.Name);
}
}
public interface MPropertyGettable : MPropertyEnumerable { }
public static class PropertyGettable {
public static object GetValue(this MPropertyGettable self, string name) {
return self.GetType().GetProperty(name).GetValue(self, null);
}
}
public interface MPropertySettable : MPropertyEnumerable { }
public static class PropertySettable {
public static void SetValue<T>(this MPropertySettable self, string name, T value) {
self.GetType().GetProperty(name).SetValue(self, value, null);
}
public static void CopyPropertiesFrom(this MPropertySettable self, MPropertyGettable other) {
self.GetProperties().Intersect(other.GetProperties()).ToList().ForEach(
property => self.SetValue(property, other.GetValue(property)));
}
}
This way, all the code to achieve the property-copying is separate from the classes that use it. You just need to reference the mixins in their interface list.
Note that this is not as robust or flexible as AutoMapper, because you might want to copy properties with different names or just some sub-set of the properties. Or it might downright fail if the properties don't provide the necessary getters or setters or their types differ. But, it still might be enough for your purposes.
This is cheap and easy. It makes use of System.Web.Script.Serialization and some extention methods for ease of use:
public static class JSONExts
{
public static string ToJSON(this object o)
{
var oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
return oSerializer.Serialize(o);
}
public static List<T> FromJSONToListOf<T>(this string jsonString)
{
var oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
return oSerializer.Deserialize<List<T>>(jsonString);
}
public static T FromJSONTo<T>(this string jsonString)
{
var oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
return oSerializer.Deserialize<T>(jsonString);
}
public static T1 ConvertViaJSON<T1>(this object o)
{
return o.ToJSON().FromJSONTo<T1>();
}
}
Here's some similiar but different classes:
public class Member
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsCitizen { get; set; }
public DateTime? Birthday { get; set; }
public string PetName { get; set; }
public int PetAge { get; set; }
public bool IsUgly { get; set; }
}
public class MemberV2
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsCitizen { get; set; }
public DateTime? Birthday { get; set; }
public string ChildName { get; set; }
public int ChildAge { get; set; }
public bool IsCute { get; set; }
}
And here's the methods in action:
var memberClass1Obj = new Member {
Name = "Steve Smith",
Age = 25,
IsCitizen = true,
Birthday = DateTime.Now.AddYears(-30),
PetName = "Rosco",
PetAge = 4,
IsUgly = true,
};
string br = "<br /><br />";
Response.Write(memberClass1Obj.ToJSON() + br); // just to show the JSON
var memberClass2Obj = memberClass1Obj.ConvertViaJSON<MemberV2>();
Response.Write(memberClass2Obj.ToJSON()); // valid fields are filled
For one thing I would not place that code (somewhere) external but in the constructor of the ViewModel:
class DefectViewModel
{
public DefectViewModel(Defect source) { ... }
}
And if this is the only class (or one of a few) I would not automate it further but write out the property assignments. Automating it looks nice but there may be more exceptions and special cases than you expect.
Any chance you could have both classes implement an interface that defines the shared properties?