Why is a default interface method used instead of a class field? - c#

I have code like below. Interface with default implementation. And the user who uses this interface. But for some reason in the switch case my code uses the default implementation of the interface for the "Name' instead of the class implementation. What should i change to see "Ben" in console?
namespace ConsoleApp1
{
public interface IUser
{
// Interface with default implementation
public string Name { get => "Tom"; }
}
// User using this interface
public class BenUser : IUser
{
public string Name = "Ben";
}
public static class MainClass
{
public static void ShowName(IUser user)
{
switch (user.Name)
{
case "Ben": // I expected the code to run here
Console.WriteLine("Ben");
break;
case "Tom": // But the code goes here
Console.WriteLine("Tom");
break;
}
}
static void Main()
{
// Create a user with Name "Ben"
var ben = new BenUser();
ShowName(ben); // In console i see "Tom" for some reason
}
}
}
I can't figure out why the code is behaving like this.

As mentioned in comments, you need to implement the interface using the same shape in your class - as a property with a get.
public interface IUser
{
// Interface with default implementation
public string Name { get => "Tom"; }
}
// User using this interface
public class BenUser : IUser
{
public string Name { get => "Ben"; }
}
public static class MainClass
{
public static void ShowName(IUser user)
{
switch (user.Name)
{
case "Ben": // I expected the code to run here
System.Console.WriteLine("Ben");
break;
case "Tom": // But the code goes here
System.Console.WriteLine("Tom");
break;
}
}
static void Main()
{
// Create a user with Name "Ben"
var ben = new BenUser();
ShowName(ben); // In console i see "Tom" for some reason
}
}

This is my edit to show some more standard practices, please read through the comments and see if it makes anything more clear. The standard practice for creating members is to use accesslevel Type VariableName { get; set; }
namespace ConsoleApp1
{
public interface IUser
{
//denotes that this is set by construction, cannot be set afterwards
public string Name { get; }
}
// User using this interface
public class BenUser : IUser
{
// Standard 'getter' only member with a compiled return value
public string Name
{
get
{
return "Ben";
}
}
}
public class User : IUser
{
// private settable string to use with construction
private string _name;
// constructor
public User(string userName)
{
// sets the private variable to desired value
_name = userName;
}
// public 'getter' that returns the set value
public string Name
{
get
{
return _name;
}
}
}
public static class MainClass
{
public static void ShowName(IUser user)
{
Console.WriteLine(user.Name);
}
static void Main()
{
// Create a user with static Name "Ben"
var ben = new BenUser();
ShowName(ben);
// Create a user with variable Name set as "Carl"
var carl = new User("Carl");
ShowName(carl);
}
}
}

The Name in IUser is a property while Name in BenUser is a field. With your code when we do user.Name it calls the get method defined in IUser instead of getting value of Name field from BenUser. Here is a sample implementation for fixing your bug.
public class BenUser : IUser
{
public string Name { get => "Ben"; }
}
I would recommend to not do it the way you are doing because Name identifier has become embiguos

Related

Custom attributes not behaving like data annotations

I am trying to create a custom attribute in console application but it is not working. My custom attribute never gets called. I found a good example here Custom Attribute not being hit
but not happy with its implementation.
I am wondering how data annotations works in MVC. we don't have to call it separately.
Is MVC calling those data annotations attribute behind the scene?
I wish to create custom attribute that I can use it on any class property same like data annotations attribute. But calling it separately like in above link is not what i am looking.
Here is what I have tried:
using System;
namespace AttributePractice
{
[AttributeUsage(AttributeTargets.Property)]
public class CustomMessageAttribute : Attribute
{
public static readonly CustomMessageAttribute Default = new CustomMessageAttribute();
protected string Message { get; set; }
public CustomMessageAttribute() : this(string.Empty)
{
Console.WriteLine("Default message is empty");
}
public CustomMessageAttribute(string message)
{
Message = message;
}
public string MyMessage =>
Message;
public override bool Equals(object obj)
{
if (obj == this)
return true;
if (obj is CustomMessageAttribute customMessageAttribute)
return customMessageAttribute.Message == MyMessage;
return false;
}
public override int GetHashCode()
{
return MyMessage.GetHashCode();
}
public override bool IsDefaultAttribute()
{
return Equals(Default);
}
}
public class Person
{
//This never works
// I am looking to use this attribute anywhere without calling it
// separately , same like data annotations
[CustomMessage("Hello world")]
public string Name { get; set; }
public int Age { get; set; }
public void DisplayPerson()
{
Console.WriteLine(Name);
Console.WriteLine(Age);
}
}
internal static class Program
{
private static void Main(string[] args)
{
var personObj = new Person
{
Name = "Tom",
Age = 28
};
personObj.DisplayPerson();
}
}
}
Can anybody tell me how to make my custom attribute works like data annotation way?
yes, if you need 10 custom attributes, you should create 10 separate.

How to correctly implement generic interface method?

I'm trying to implement generic interface method but keep getting an error. I'm pasting the code to better explain what I want to do.
What I'm trying to achieve is: based on some input data (SomeModelA, SomeModelB) I want to get the same return type (Template).
namespace GenericInterfacePuzzle
{
class Program
{
static void Main(string[] args)
{
var workerA = new WorkerA();
var itemsBasedOnModelA = workerA.Get(new List<SomeModelA>());
var workerB = new WorkerB();
var itemsBasedOnModelB = workerB.Get(new List<SomeModelB>());
}
}
public interface IWorker
{
Template Get<T>(List<T> someModels);
}
public class WorkerA : IWorker
{
public Template Get<SomeModelA>(List<SomeModelA> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelA> models)
{
var x = models.First();
}
}
public class WorkerB : IWorker
{
public Template Get<SomeModelB>(List<SomeModelB> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelB> models)
{
var x = models.First();
}
}
public class SomeModelA
{
public string Name { get; set; }
}
public class SomeModelB
{
public string Age { get; set; }
}
public class Template
{
// Irrevelant return type
}
}
I want to know at the level of WorkerA/WorkerB class that I'm dealing with a concrete model, and based on that I want to return a Template class instance
The problem is that in the lines that call Process:
ProcessModels(someModels);
I get an error saying:
Error CS1503 Argument 1: cannot convert from 'System.Collections.Generic.List of SomeModelA' to 'System.Collections.Generic.List of GenericInterfacePuzzle.SomeModelA'
Any feedback appreciated what might be going wrong here, and why doesn't it recognize the model classes when passed to the functions.
Chris
1) You need to define the generic parameter on the level of your interface. Otherwise the T parameter is not known to the compiler:
public interface IWorker<T> where T: SomeModel
{
Template Get(List<T> someModels);
}
2) you need to make a constraint since you probably don't want any type to be given to your interface. It would be preferable to make a baseclass for your models and let them inherit from it:
public abstract class SomeModel { ... }
public class SomeModelA : SomeModel
{
public string Name { get; set; }
}
public class SomeModelB : SomeModel
{
public string Age { get; set; }
}
This way it will allow you to specify the model directly in the declaration of the class which will implement the interface (see point 3)
3) Now you need to specify in the child classes which model belongs to which workertype:
public class WorkerA : IWorker<SomeModelA>
{
public Template Get(List<SomeModelA> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelA> models)
{
var x = models.First();
}
}
public class WorkerB : IWorker<SomeModelB>
{
public Template Get(List<SomeModelB> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelB> models)
{
var x = models.First();
}
}
You also should remove the generic specification in your Get method!
public Template Get<SomeModelA>(List<SomeModelA> someModels)
^
|
remove this
this is already specified when you implement the interface:
public class WorkerA : IWorker<SomeModelA>
4) and the last thing is you test in the main method:
var worker = new WorkerA();
var itemsBasedOnModelA = worker.Get(new List<SomeModelA>());
var workerB = new WorkerB();
var itemsBasedOnModelB = worker.Get(new List<SomeModelB>());
^
|
this should be [workerB]!

Same interface different ctor implementaion

I have and in interface ICalibrationToolsLoader
namespace Utilities.Interfaces
{
public interface ICalibrationToolsLoader
{
string GetDefaultIspFile(string selectedSensorType = null);
IspSectionUiSettings GetIspSectionUiSettings();
List<CalibrationGroup> GetCmcGroupOrder();
}
}
and two classes implements it.
public class Ipu6CalibraitionToolsLoader : ICalibrationToolsLoader
{
private string _selectedSensorType;
public Ipu6CalibraitionToolsLoader(string selectedSensorType)
{
_selectedSensorType = selectedSensorType;
_ispSectionUiSettings = Serialization.DataContract.Deserialize<IspSectionUiSettings>(GetDefaultIspFile(_selectedSensorType));
InitCmcOrder();
}
public string GetDefaultIspFile(string selectedSensorType = null)
{
string location = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string pathSuffix = null;
switch ((IPU6SensorType)Enum.Parse(typeof(IPU6SensorType), selectedSensorType))
{
case IPU6SensorType.None:
break;
case IPU6SensorType.Bayer:
pathSuffix = "IPUs\\IPU6\\IPU6DefaultsIspFile.xml";
break;
case IPU6SensorType.MD:
pathSuffix = "IPUs\\IPU6\\IPU6MdDefaultsIspFile.xml";
break;
default:
throw new ArgumentOutOfRangeException("selectedSensorType", selectedSensorType, null);
}
if (pathSuffix != null)
{
string path = Path.Combine(location, pathSuffix);
return path;
}
throw new Exception("missing defaultIspFileXml");
}
public void InitCmcOrder()
{
_cmcCalibrationToolsOrder = new List<CalibrationGroup>
{
CalibrationGroup.GeneralDataTools,
CalibrationGroup.SensorAndModuleSettingsTools,
CalibrationGroup.LateralChromaticAberrationTool,
};
}
}
public class Ipu4CalibraitionToolsLoader : ICalibrationToolsLoader
{
public Ipu4CalibraitionToolsLoader()
{
_ispSectionUiSettings = Serialization.DataContract.Deserialize<IspSectionUiSettings>(GetDefaultIspFile());
InitCmcOrder();
}
public string GetDefaultIspFile(string selectedSensorType = null)
{
string location = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string pathSuffix = "IPUs\\Broxton\\IPU4DefaultsIspFile.xml";
string path = Path.Combine(location, pathSuffix);
return path;
}
public void InitCmcOrder()
{
_cmcCalibrationToolsOrder = new List<CalibrationGroup>
{
CalibrationGroup.GeneralDataTools,
CalibrationGroup.SensorAndModuleSettingsTools,
CalibrationGroup.LateralChromaticAberrationTool,
};
}
}
basically most of the functions are the same however, functions like the constructor and GetDefaultIsp needs to have different implementation.
I tried to use inheritance but calling a virtual function inside the constructor is a big NO NO.
Can you suggest of another way of doing so?
having 2 classes using the same interface however some methods should have different implementation?
I don't want to have another function like Init() which needs to be called after the constructor.
EDIT: Addition of the IoC implementation to solve your issue!
IoC Version
The IoC solution is, in my opinion, way more elegant but probably a little bit more complicated to maintain when you are not used to IoC.
Credits goes to plalx for suggesting it in the comments :D.
// There is no need for an interface anymore (but you can keep it of course)
public class IpuCalibrationToolsLoader
{
private string _selectedSensorType;
private string _ispSectionUiSettings;
private List<CalibrationGroup> _cmcCalibrationToolsOrder;
public IIspFileProvider Provider { get; private set; }
// Notice the internal constructor. No one will be able to create an instance of IpuCalibrationToolsLoader out of your assembly except the factory
internal IpuCalibrationToolsLoader(IIspFileProvider provider, string selectedSensorType = null)
{
this.Provider = provider;
_selectedSensorType = selectedSensorType;
_ispSectionUiSettings = Serialization.DataContract.Deserialize<IspSectionUiSettings>(provider.GetDefaultIspFile(_selectedSensorType));
this.InitCmcOrder();
}
public void InitCmcOrder()
{
_cmcCalibrationToolsOrder = new List<CalibrationGroup>
{
CalibrationGroup.GeneralDataTools,
CalibrationGroup.SensorAndModuleSettingsTools,
CalibrationGroup.LateralChromaticAberrationTool,
};
}
[..] // Since the Provider is exposed as a properties of your IpuCalibrationClassLoader, there is no need for defining the GetDefaultIspFile methods within this class
}
public interface IIspFileProvider
{
string GetDefaultIspFile(string selectedSensorType = null);
}
public class Ipu6FileProvider : IIspFileProvider
{
public string GetDefaultIspFile(string selectedSensorType = null)
{
string location = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string pathSuffix = null;
switch ((IPU6SensorType)Enum.Parse(typeof(IPU6SensorType), selectedSensorType))
{
case IPU6SensorType.None:
break;
case IPU6SensorType.Bayer:
pathSuffix = "IPUs\\IPU6\\IPU6DefaultsIspFile.xml";
break;
case IPU6SensorType.MD:
pathSuffix = "IPUs\\IPU6\\IPU6MdDefaultsIspFile.xml";
break;
default:
throw new ArgumentOutOfRangeException("selectedSensorType", selectedSensorType, null);
}
if (pathSuffix != null)
{
string path = Path.Combine(location, pathSuffix);
return path;
}
throw new Exception("missing defaultIspFileXml");
}
}
public class Ipu4FileProvider : IIspFileProvider
{
public string GetDefaultIspFile(string selectedSensorType = null)
{
string location = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string pathSuffix = "IPUs\\Broxton\\IPU4DefaultsIspFile.xml";
string path = Path.Combine(location, pathSuffix);
return path;
}
}
public static class IpuCalibrationToolsLoaderFactory
{
public static IpuCalibrationToolsLoader GetIpu4CalibrationToolsLoader()
{
return new IpuCalibrationToolsLoader(new Ipu4FileProvider());
}
public static IpuCalibrationToolsLoader GetIpu6CalibrationToolsLoader(string selectedSensorType)
{
return new IpuCalibrationToolsLoader(new Ipu6FileProvider(), selectedSensorType);
}
}
Inheritance version
Here is the version using an abstract class. An abstract class is a class you cannot instantiate. It only holds some code:
public abstract class BaseCalibrationToolsLoader : ICalibrationToolsLoader
{
public BaseCalibrationToolsLoader()
{
// put here the shared constructor code
_cmcCalibrationToolsOrder = new List<CalibrationGroup>
{
CalibrationGroup.GeneralDataTools,
CalibrationGroup.SensorAndModuleSettingsTools,
CalibrationGroup.LateralChromaticAberrationTool,
};
}
public List<CalibrationGroup> GetCmcGroupOrder()
{
// Put here the shared code among the two implementation
}
// As the implementation is different, you declare the method abstract so you only implement it in the concret classes
public abstract string GetDefaultIspFile(string selectedSensorType = null);
}
Now, you can create your concrete implementation that derived from the abstract class:
public class Ipu4CalibraitionToolsLoader : BaseCalibrationToolsLoader
{
public Ipu4CalibraitionToolsLoader ()
: base() // <- call the protected constructor
{
// put here the specific implementation constructor code
// notice that the constructor of the abstract class will **ALWAYS** be call before this code
_ispSectionUiSettings = Serialization.DataContract.Deserialize<IspSectionUiSettings>(GetDefaultIspFile());
}
// The GetCmcGroupOrder is already implemented, nothing to do about it
// With the sealed keyword, the method cannot be overriden in another class
public sealed override void GetDefaultIsp(string selectedSensorType = null)
{
// put here the concrete implementation for Ipu4
}
}
public class Ipu6CalibraitionToolsLoader: BaseCalibrationToolsLoader
{
public Ipu6CalibraitionToolsLoader(string selectedSensorType)
: base() // <- call the protected constructor
{
// put here the specific implementation constructor code
// notice that the constructor of the abstract class will **ALWAYS** be call before this code
_selectedSensorType = selectedSensorType;
_ispSectionUiSettings = Serialization.DataContract.Deserialize<IspSectionUiSettings>(GetDefaultIspFile(_selectedSensorType));
}
// The GetCmcGroupOrder is already implemented, nothing to do about it
// With the sealed keyword, the method cannot be overriden in another class
public sealed override void GetDefaultIsp(string selectedSensorType = null)
{
// put here the concrete implementation for Ipu6
}
}
As for the abstract constructor, you can define a virtual method in the abstract class and call it in the concrete implementation, in order to share a part of the code:
public abstract class BaseCalibrationToolsLoader : ICalibrationToolsLoader
{
[..]
// By using the virtual keyword, you allow your method to be overriden in the derived classes
public virtual void PartiallySharedMethod()
{
// Shared implementation
}
[..]
}
And in the concrete implementations:
public class Ipu4CalibraitionToolsLoader : BaseCalibrationToolsLoader
{
[..]
public override void PartiallySharedMethod()
{
// Unlike in the constructor, you can call the base method whenever you want.
// Some specific code can came here
base.PartiallySharedMethod();
// And other specific code can also came here
}
[..]
}
public class Ipu6CalibraitionToolsLoader: BaseCalibrationToolsLoader
{
[..]
public override void PartiallySharedMethod()
{
// Unlike in the constructor, you can call the base method whenever you want.
// Some specific code can came here
base.PartiallySharedMethod();
// And other specific code can also came here
}
[..]
}

Inject a string property in a class using Ninject

One of my interfaces has a string property that will depend on where the interface is being used. I want to avoid hardcoding the property every time the object is created. I can set the property in constructor, but the object is injected using a factory.
The interface as follows:
public interface IObjectStore
{
string StorageTableName { get; set;}
void UpdateObjectStore(string key, string value);
string ReadObjectStore(string key);
}
Which is used in a service
public class CategoryService<T> : ICategoryService<T> where T : Company
{
private readonly IObjectStore objectStore;
public CategoryService(IObjectStore objStore)
{
this.objectStore = objStore;
objectStore.StorageTableName = "CategoryTable"; // I want to avoid this hard coding
}
...
}
The service is created using service factory (Ninject.Extensions.Factory)
public interface IServiceFactory
{
ICategoryService<T> CreateCategoryService<T>() where T : class;
}
Which is then injected using Ninject at the controller level. Here are my bindings
bool storeInNoSql = true;
kernel.Bind<IServiceFactory>().ToFactory().InSingletonScope();
kernel.Bind<ICategoryService<Article>>().To<CategoryService<Article>>();
kernel.Bind<IObjectStore>().ToMethod(ctx => storeInNoSql ? ctx.Kernel.Get<ObjectStore>() : null);
So the question is: how do i tell Ninject to set the property StorageTableName to "CategoryTable" everytime the object is injected into CategoryService and to "ArticleTable" everytime it is inserted into ArticleService?
I think this is what you are looking for.
It's just a very small sample project I just did, but this should solve your problem.
public class Ninject_34091099
{
public static void Run()
{
using (IKernel kernel = new StandardKernel())
{
kernel.Bind<IInterface<Generic1>>()
.To<Class<Generic1>>()
.WithConstructorArgument("name", "STRING ONE");
kernel.Bind<IInterface<Generic2>>()
.To<Class<Generic2>>()
.WithConstructorArgument("name", "The other string");
kernel.Bind<IServiceFactory>().ToFactory().InSingletonScope();
var factory = kernel.Get<IServiceFactory>();
var c1 = factory.CreateInterface<Generic1>();
var c2 = factory.CreateInterface<Generic2>();
Console.WriteLine(c1.Name);
Console.WriteLine(c2.Name);
}
Console.WriteLine("Done");
Console.ReadLine();
}
}
public interface IInterface<T> where T : class
{
string Name { get; set; }
}
public class Generic1
{
}
public class Generic2
{
}
public class Class<T> : IInterface<T> where T : class
{
public string Name { get; set; }
public Class(string name)
{
Name = name;
}
}
public interface IServiceFactory
{
IInterface<T> CreateInterface<T>() where T : class;
}
Sorry that the names mean nothing :D
Hope it helps

Unable to perform cast

I need to have a wrapper class that exposes some properties of my entity class called ProfileEntity.
I tried doing it by deriving from this entity and then creating properties that return specific entity properties, but it says I cannot cast from ProfileEntity to ProfileEntityWrapper.
When I try to put the return values of a method that returns a 'ProfileEntity' into the wrapper I get the above error.
How do I create such a wrapper class that is castable?
Example
class ProfileEntityWrapper : ProfileEntity
{
public string Name
{
get
{
return this.ProfileEntityName;
}
}
}
public class Someclass
{
public ProfileEntity SomeMethod()
{
return ProfileEntity; // example of method returning this object
}
}
public class SomeOtherlClass
{
SomeClass sc = new SomeClass();
public void DoSomething()
{
ProfileEntityWrapper ew = (ProfileEntityWrapper)sc.SomeMethod(); // Cannot do this cast!!!
}
}
You cannot cast an object of ProfileEntity to ProfileEntityWrapper.
var entity = new ProfileEntity(); // this object is only of type ProfileEntity
var wrapper = new ProfileEntityWrapper(); // this object can be used as both ProfileEntityWrapper and ProfileEntity
You probably want to return a ProfileEntityWrapper in SomeMethod():
public class Someclass
{
public ProfileEntity SomeMethod()
{
return new ProfileEntityWrapper(); // it's legal to return a ProfileEntity
}
}
No, that is not possible.
To accomplish this problem you can maybe try this one:
public class ProfileEntity
{
public string ProfileEntityName { get; set; }
}
public class ProfileEntityWrapper
{
public ProfileEntityWrapper(ProfileEntity entity)
{
Entity = entity;
}
public ProfileEntity Entity { get; private set; }
public string Name
{
get
{
return Entity.ProfileEntityName;
}
}
}
public class SomeClass
{
public ProfileEntity SomeMethod()
{
// example of method returning this object
ProfileEntity temp = new ProfileEntity();
return temp;
}
}
public class SomeOtherClass
{
SomeClass sc = new SomeClass();
public void DoSomething()
{
//Create a new Wrapper for an existing Entity
ProfileEntityWrapper ew = new ProfileEntityWrapper(sc.SomeMethod());
}
}
If you are allowed to edit the ProfileEntity class, or if the ProfileEntity class is a generated partial class, you could add an interface instead of using a wrapper. You wouldn't need to do any casting with an interface either. Example:
public interface IProfile
{
string Name { get; }
}
public partial class ProfileEntity : IProfile
{
public string Name
{
get
{
return this.ProfileEntityName;
}
}
}
public class SomeClass
{
public ProfileEntity SomeMethod()
{
return ProfileEntity;
}
}
public class SomeOtherClass
{
SomeClass sc = new SomeClass();
public void DoSomething()
{
IProfile ew = sc.SomeMethod();
}
}
The IProfile instance will only provide access to the Name property.
This's no correct code from polymorphism aspect.
If we will take the famous polymorphism example when there're base Shape class and Circle, Polygon and Rectangle classes that extend the Shape class, your code will try to cast some shape into circle and as you understand this's invalid casting operation.
So to make this code work you must be sure that SomeClass.SomeMethod() will return instance of ProfileEntityWrapper or perform type check before the casting, like this:
ProfileEntity temp = sc.SomeMethod();
if(temp is ProfileEntityWrapper)
ProfileEntityWrapper ew = (ProfileEntityWrapper) temp;

Categories

Resources